home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / rhstdlib.arc / STDLIB.TXT < prev    next >
Encoding:
Text File  |  1990-10-20  |  103.9 KB  |  2,994 lines

  1. 1 Randy Hyde's Standard Library for 8086 Assembly Language Programmers
  2.  
  3.      This software is ...
  4.  
  5.   sssssss      ss     ss       ss       sssssss     sssssss
  6.   ss           ss     ss      ssss      ss    ss    ss
  7.   ss           ss     ss     ss  ss     ss    ss    ss
  8.   sssssss      sssssssss    ssssssss    sssssss     sssss        ssssssss
  9.        ss      ss     ss    ss    ss    ss ss       ss
  10.        ss      ss     ss    ss    ss    ss  ss      ss
  11.   sssssss      ss     ss    ss    ss    ss   ss     sssssss
  12.  
  13.  
  14.  
  15.   ww                  ww       ww       sssssss     sssssss
  16.    ww                ww       wwww      ss    ss    ss
  17.     ww      ww      ww       ww  ww     ss    ss    ss
  18.      ww    wwww    ww       wwwwwwww    sssssss     sssss
  19.       ww  ww  ww  ww        ww    ww    ss ss       ss
  20.        wwww    wwww         ww    ww    ss  ss      ss
  21.         ww      ww          ww    ww    ss   ss     sssssss
  22.  
  23.  
  24.  
  25.                   'cuz I'm sharing it with you!
  26.  
  27.  
  28.      I do not want any registrations or fees for the use of this software.  I
  29. thank God and Jesus Christ (my personal saviour) for giving me the ability to
  30. write such software.  God wants all of us to use our talents to glorify him,
  31. therefore I offer this software as such.
  32.  
  33.      Now for the catch...  It is more blessed to give than to receive.  If this
  34. software saves you time and effort and you enjoy using it, my life will be
  35. enriched knowing that others have appreciated my work.  I would like to share
  36. this wonderful feeling with you.  If you like this software and use it, I would
  37. like you to contribute at least one routine to the library.  Perhaps you think
  38. this library has some neet-o routines in it.  Imagine how nice it would become
  39. if everyone used their imagination to contribute something useful to it.
  40.  
  41.      I hereby release this software to the public domain.  You can use it in
  42. any way you see fit.  However, I would appreciate it if you share this software
  43. with other much as I've shared it with you.  I'm not suggesting that you give
  44. away software you've written with this package (I'm not quite as crazy as
  45. Richard Stallman, bless his heart), but if someone else would like a copy of
  46. this library, please help them out.  Naturally, I'd be tickeled pink to receive
  47. credit in software that uses these routines (which is the honorable thing to
  48. do) but I understand the way many corporations operate and won't be terrible
  49. put off if you use it without giving due credit.  Enjoy!
  50.  
  51.      If you have comments, bug reports, new code to contribute, etc., you can
  52. reach me at:
  53.  
  54.           rhyde                    (On BIX).
  55.           rhyde@cs.ucr.edu         (On Internet).
  56.           rhyde@ucrmath.ucr.edu    (On Internet, this one may go away).
  57.  
  58. or
  59.  
  60.           Randy Hyde
  61.           Dept of Computer Science
  62.           2208 Sproul Hall
  63.           University of California
  64.           Riverside, Ca. 92521-0135
  65. or
  66.           Randy Hyde
  67.           c/o Braintec Corporation
  68.           10 Corporate Park Way, ste 110
  69.           Irvine, Ca.  92714
  70.  
  71.  
  72. 1.1 Comments about the code
  73.  
  74.      This code has received very little testing.  C'mon, whadda expect for
  75. free?  I've been cranking this stuff out as fast as possible without going back
  76. and reworking anything I've done.  The only exception has been modification of
  77. the routines to use the es:di/dx:si register pairs rather than es:si/ds:di
  78. register pairs.  I expect those modifications introduced more bugs.  Please
  79. don't expect super optimal code here.  I have had anytime to study and improve
  80. this code.  Most of it is fairly mediocre (from a size/speed point of view).
  81. Hopefully, you'll agree, it's the idea that counts.  If you don't like
  82. something I've done, you've got the sources -- have at it.  (Of course, I'd
  83. appreciate it if you would send me any modifications.)
  84.  
  85.  
  86.  
  87. 1.2 Wish List
  88.  
  89.      Next, I'll be working on FILE I/O versions of the I/O routines in this
  90. package.  Sooner or later I'll get around to adding floating point routines to
  91. this package.  If you're interested in adding some routines to this package,
  92. GREAT!
  93.  
  94.      Routines I'd like to have but am too busy to work on now:
  95.  
  96.      1) Routines which manipulate directories (read/write/etc.)
  97.  
  98.      2) A regular expression interpreter.
  99.  
  100.      3) Length-prefixed strings package.
  101.  
  102.      4) A windowing package.
  103.  
  104.      5) A graphics package.
  105.  
  106.      6) An object-oriented programming class library.
  107.  
  108.      7) Just about anything else appearing in a HLL "standard" library.
  109.  
  110.      If you've got any ideas, I'd love to discuss them with you.  Best bet is
  111. to reach me electronically at the E-MAIL addresses above.
  112.  
  113.  
  114. 1.3 Missing Routines to Supply RSN
  115.  
  116.      String package:
  117.  
  118. strins       Inserts one string into the middle of another
  119.  
  120. strdel       Deletes a sequence of characters from the middle of a string.
  121.  
  122.      Character Set Package:
  123.  
  124. span-        Skips through a sequence of characters in a string which belong to
  125.              a character set.
  126.  
  127. break-       Skips through a sequence of characters in a string which do not
  128.              belong to a character set.
  129.  
  130.      Memory Manager Package
  131.  
  132. Memavail-    Largest block of free memory available on the heap.
  133.  
  134. Memfree-     Total amount of free space on the heap.
  135.  
  136.  
  137.  
  138. 2 Character Output Routines
  139.  
  140. 2.1 Putc
  141.  
  142. *          Outputs character in AL register to the standard output device.
  143.  
  144. *          Output is redirectable to user-written routine.
  145.  
  146. Inputs:    AL- character to print.
  147.  
  148. Outputs:   None.
  149.  
  150. Include:   stdlib.a
  151.  
  152. Putc is the primitive character output routine.  Most other output routines in
  153.            the standard library output data through this procedure.  Prints the
  154.            ASCII character in AL.  Processing of control codes is undefined
  155.            although most output routines this guy links to should be able to
  156.            handle return, line feed, back space, and tab.  By default, this
  157.            routine calls DOS to print the character to the standard output
  158.            device.
  159.  
  160.      Example:
  161.  
  162.                      mov     al, 'C'
  163.                      putc                    ;Prints "C" to std output.
  164.  
  165.  
  166. 2.2 PutCR
  167.  
  168. *          Easy way of printing a newline to the stdlib standard output.
  169.  
  170. Inputs:    None.
  171.  
  172. Outputs:   None.
  173.  
  174. Include:   stdlib.a
  175.  
  176.      Prints a newline (carriage return/line feed) to the current standard
  177. output device.
  178.  
  179.      Example:
  180.  
  181.                      PutCR
  182.  
  183.  
  184. 2.3 PutcStdOut
  185.  
  186. *          Outputs character in AL to the DOS standard output device.
  187.  
  188. *          Sends a character directly to the DOS std output device.
  189.  
  190. *          Output is redirectable via DOS I/O redirection.
  191.  
  192. *          Bypasses redirection through the standard library Putc routine.
  193.  
  194. Inputs:    AL- character to output.
  195.  
  196. Outputs:   None.
  197.  
  198. Include:   stdlib.a
  199.  
  200.      PutcStdOut calls DOS to print the character in AL to the standard output
  201. device.  Although processing of non-ASCII characters and control characters is
  202. undefined, most output devices handle these characters properly.  In
  203. particular, most output devices properly handle return, line feed, back space,
  204. and tab.
  205.  
  206.      Example:
  207.  
  208.                      mov     al, 'C'
  209.                      PutcStdOut              ;Writes "C" to std output.
  210.  
  211.  
  212. 2.4 PutcBIOS
  213.  
  214. *          Prints character in AL to the display device by calling BIOS.
  215.  
  216. *          Cannot be redirected by stdlib or by DOS.
  217.  
  218. *          Uses INT 10H/AH=14 for teletype-like output.
  219.  
  220. *          Handles return, line feed, back space, and tab.  Prints other
  221.            control characters using the IBM Character set.
  222.  
  223. Inputs:    AL- Character to print.
  224.  
  225. Outputs:   None.
  226.  
  227. Include-   stdlib.a
  228.  
  229.      PutcBIOS prints the character in AL using the BIOS routines.  Output
  230. through this routine cannot be redirected, such output is always sent to the
  231. video display on the PC (unless, of course, someone has patched INT 10h).
  232.  
  233.      Example:
  234.  
  235.                      mov     al, "C"
  236.                      PutcBIOS
  237.  
  238.  
  239. 2.5 GetOutAdrs
  240.  
  241. *          Retrieves address of the current output routine.
  242.  
  243. Inputs:    None.
  244.  
  245. Outputs:   es:di - address of current output routine (called by Putc).
  246.  
  247. Include:   stdlib.a
  248.  
  249.      You can use this function to get the address of the current output
  250. routine, perhaps so you can save it or see if it is currently pointing at some
  251. particular piece of code.  If you want to temporarily redirect the output and
  252. then restore the original output routine, consider using PushOutAdrs/PopOutAdrs
  253. described later.
  254.  
  255.      Example:
  256.  
  257.                      GetOutAdrs
  258.                      mov     word ptr SaveOutAdrs, di
  259.                      mov     word ptr SaveOutAdrs+2, es
  260.  
  261.  
  262. 2.6 SetOutAdrs
  263.  
  264. *          Lets you set the address of the current output routine.
  265.  
  266. Inputs:    es:di- Address of new output routine.
  267.  
  268. Outputs:   None.
  269.  
  270. Include:   stdlib.a
  271.  
  272.      This routine redirects the stdlib standard output so that it calls the
  273. routine whose address you pass in es:di.  This routine should expect the
  274. character in AL and must preserve all registers.  At a bare minimum, it should
  275. handle the printable ASCII characters and the four control characters return,
  276. line feed, back space, and tab (unless, of course, the main purpose of this
  277. routine is to handle these codes in a different fashion).
  278.  
  279.      Example:
  280.  
  281.                      mov     es, seg NewOutputRoutine
  282.                      mov     di, offset NewOutputRoutine
  283.                      SetOutAdrs
  284.                         .
  285.                         .
  286.                         .
  287.                      les     di, RoutinePtr
  288.                      SetOutAdrs
  289.  
  290.  
  291. 2.7 PushOutAdrs
  292.  
  293. *          Lets you redirect the standard output device and preserve the
  294.            previous address.
  295.  
  296. *          Saves up to 16 old output routine addresses on an internal stack.
  297.  
  298. *          Restoration is possible using PopOutAdrs.
  299.  
  300. Inputs:    es:di- Address of new output routine.
  301.  
  302. Outputs:   Carry=0 if operation successful.
  303.            Carry=1 if there were already 16 items on the stack.
  304.  
  305. Include:   stdlib.a
  306.  
  307.      This routine "pushes" the current output address onto an internal stack
  308. and then stores the value in es:di into the current output routine pointer.
  309. The PushOutAdrs and PopOutAdrs routines let you easily save and redirect the
  310. standard output and then restore the original output routine address later on.
  311.  
  312.      If you attempt to push more than 16 items on the stack, PushOutAdrs will
  313. ignore your request and return with the carry flag set.  If PushOutAdrs is
  314. successful, it will return with the carry flag clear.
  315.  
  316.      Example:
  317.  
  318.                      mov     es, seg NewOutputRoutine
  319.                      mov     di, offset NewOutputRoutine
  320.                      PushOutAdrs
  321.                         .
  322.                         .
  323.                         .
  324.                      les     di, RoutinePtr
  325.                      PushOutAdrs
  326.  
  327.  
  328. 2.8 PopOutAdrs
  329.  
  330. *          Restores output routine addresses saved by PushOutAdrs.
  331.  
  332. *          Defaults to PutcStdOut if you attempt to pop too many items off the
  333.            stack.
  334.  
  335. Inputs:    None.
  336.  
  337. Outputs:   es:di- Points at the previous stdout routine before the pop.
  338.  
  339. Include:   stdlib.a
  340.  
  341.      PopOutAdrs undoes the effects of PushOutAdrs.  It pops an item off the
  342. internal stack and stores it into the output routine pointer.  The previous
  343. value in the output pointer is returned in es:di.
  344.  
  345.      Example:
  346.  
  347.                      mov     es, seg NewOutputRoutine
  348.                      mov     di, offset NewOutputRoutine
  349.                      PushOutAdrs
  350.                         .
  351.                         .
  352.                         .
  353.                      PopOutAdrs
  354.  
  355.  
  356. 2.9 Puts
  357.  
  358. *          Outputs a string of characters to the stdlib standard output device.
  359.  
  360. *          Calls putc for each character in the string thereby sending each
  361.            character out to the standard output device.
  362.  
  363. Inputs:    es:di- Contains the address of the string to print.
  364.  
  365. Outputs:   None.
  366.  
  367. Include:   stdlib.a
  368.  
  369.      Puts prints a zero-terminated string whose address appears in es:di.  Each
  370. character appearing in the string is printed verbatim.  There are no special
  371. escape characters.  Unlike the "C" routine by the same name, puts does not
  372. print a newline after printing the string.  Use putcr if you want to print the
  373. newline after printing a string with puts.
  374.  
  375.      Example:
  376.  
  377.                      les     di, StrToPrt
  378.                      puts
  379.                      putcr
  380.  
  381.  
  382. 2.10 Puth
  383.  
  384. *          Outputs the byte in AL as two hex digits (including leading zero if
  385.            necessary).
  386.  
  387. *          Calls stdlib putc routine to print both characters to the stdlib
  388.            standard output device.
  389.  
  390. Inputs:    AL- Value to print.
  391.  
  392. Outputs:   None.
  393.  
  394. Include:   Stdlib.a
  395.  
  396.      Prints the value in the AL register as two hexadecimal digits.  If the
  397. value in AL is between 0 and 0Fh, puth will print a leading zero.  This routine
  398. calls the stdlib standard output routine (putc) to print all characters.
  399.  
  400.      Example:
  401.  
  402.                      mov     al, 1fh
  403.                      puth
  404.  
  405.  
  406. 2.11 Putw
  407.  
  408. *          Outputs the word in AX as four hex digits (including leading zeros
  409.            if necessary).
  410.  
  411. *          Calls stdlib putc routine to print characters to the stdlib standard
  412.            output device.
  413.  
  414. Inputs:    AX- Value to print.
  415.  
  416. Outputs:   None.
  417.  
  418. Include:   Stdlib.a
  419.  
  420.      Prints the value in the AX register as four hexadecimal digits.  If the
  421. value in AX is between 0 and 0Fh, puth will print a leading zero.  This routine
  422. calls the stdlib standard output routine (putc) to print all characters.
  423.  
  424.      Example:
  425.  
  426.                      mov     ax, 0f1fh
  427.                      putw
  428.  
  429.  
  430. 2.12 Puti
  431.  
  432. *          Outputs the word in AX as a signed decimal number (including minus
  433.            sign, if necessary).
  434.  
  435. *          Calls stdlib putc routine to print characters to the stdlib standard
  436.            output device.
  437.  
  438. Inputs:    AX- Value to print.
  439.  
  440. Outputs:   None.
  441.  
  442. Include:   Stdlib.a
  443.  
  444.      Prints the value in the AX register as a decimal integer.  This routine
  445. uses the exact number of screen positions required to print the number
  446. (including a position for the minus sign, if the number is negative).  This
  447. routine calls the stdlib standard output routine (putc) to print all
  448. characters.
  449.  
  450.      Example:
  451.  
  452.                      mov     ax, -1234
  453.                      puti
  454.  
  455.  
  456. 2.13 Putu
  457.  
  458. *          Outputs the word in AX as an unsigned decimal number.
  459.  
  460. *          Calls stdlib putc routine to print both characters to the stdlib
  461.            standard output device.
  462.  
  463. Inputs:    AX- Value to print.
  464.  
  465. Outputs:   None.
  466.  
  467. Include:   Stdlib.a
  468.  
  469.      Prints the value in the AX register as a decimal integer.  This routine
  470. uses the exact number of screen positions required to print the number.  This
  471. routine calls the stdlib standard output routine (putc) to print all
  472. characters.
  473.  
  474.      Example:
  475.  
  476.                      mov     ax, 1234
  477.                      putu
  478.  
  479.  
  480. 2.14 Putl
  481.  
  482. *          Outputs the double word in DX:AX as a signed decimal number
  483.            (including minus sign, if necessary).
  484.  
  485. *          Calls stdlib putc routine to print characters to the stdlib standard
  486.            output device.
  487.  
  488. Inputs:    DX:AX- Value to print.
  489.  
  490. Outputs:   None.
  491.  
  492. Include:   Stdlib.a
  493.  
  494.      Prints the value in the DX:AX registers as a decimal integer.  This
  495. routine uses the exact number of screen positions required to print the number
  496. (including a position for the minus sign, if the number is negative).  This
  497. routine calls the stdlib standard output routine (putc) to print all
  498. characters.
  499.  
  500.      Example:
  501.  
  502.                      mov     dx, 0ffffh
  503.                      mov     ax, -1234
  504.                      putl
  505.  
  506.  
  507. 2.15 Putul
  508.  
  509. *          Outputs the double word in DX:AX as an unsigned decimal number
  510.            (including minus sign, if necessary).
  511.  
  512. *          Calls stdlib putc routine to print characters to the stdlib standard
  513.            output device.
  514.  
  515. Inputs:    DX:AX- Value to print.
  516.  
  517. Outputs:   None.
  518.  
  519. Include:   Stdlib.a
  520.  
  521.      Prints the value in the DX:AX registers as a decimal integer.  This
  522. routine uses the exact number of screen positions required to print the
  523. number.  This routine calls the stdlib standard output routine (putc) to print
  524. all characters.
  525.  
  526.      Example:
  527.  
  528.                      mov     dx, 12h
  529.                      mov     ax, 1234
  530.                      putul
  531.  
  532.  
  533. 2.16 PutISize
  534.  
  535. *          Prints the value in AX as a signed decimal integer.
  536.  
  537. *          Prints the number in a minimum field width specified by the value in
  538.            CX.
  539.  
  540. Inputs:    AX- Value to print.
  541.            CX- Minimum number of print positions to use.
  542.  
  543. Outputs:   None.
  544.  
  545. Include:   Stdlib.a
  546.  
  547.       PutISize prints the signed integer value in AX to the stdlib standard
  548. output device using a minimum of n print positions.  CX contains n, the minimum
  549. field width for the output value.  The number (including any necessary minus
  550. sign) is printed right justified in the output field.
  551.  
  552.      If the number in AX requires more print positions than specified by CX,
  553. PutISize uses however many print positions are necessary to actually print the
  554. number.  If you specify zero in CX, PutISize uses the minimum number of print
  555. positions required.  Of course, PutI will also use the minimum number of print
  556. positions without disturbing the value in the CX register.
  557.  
  558.      Note that, under no circumstances, will the number in AX ever require more
  559. than size print positions (-32,767 requires the most print positions).
  560.  
  561.      Examples:
  562.  
  563.                      mov     cx, 5
  564.                      mov     ax, I
  565.                      PutISize
  566.                       .
  567.                       .
  568.                       .
  569.                      mov     cx, 12
  570.                      mov     ax, J
  571.                      PutISize
  572.  
  573.  
  574. 2.17 PutUSize
  575.  
  576. *          Prints the value in AX as an unsigned decimal integer.
  577.  
  578. *          Prints the number in a minimum field width specified by the value in
  579.            CX.
  580.  
  581. Inputs:    AX- Value to print.
  582.            CX- Minimum number of print positions to use.
  583.  
  584. Outputs:   None.
  585.  
  586. Include:   Stdlib.a
  587.  
  588.      Like PutISize above except this guy prints unsigned values.  Note that the
  589. maximum number of print positions required by any number (e.g., 65,535) is
  590. five.
  591.  
  592.      Example:
  593.  
  594.                      mov     cx, 8
  595.                      mov     ax, U
  596.                      PutUSize
  597.  
  598.  
  599. 2.18 PutLSize
  600.  
  601. *          Prints the value in DX:AX as a long signed decimal integer.
  602.  
  603. *          Prints the number in a minimum field width specified by the value in
  604.            CX.
  605.  
  606. Inputs:    DX:AX- Value to print.
  607.            CX- Minimum number of print positions to use.
  608.  
  609. Outputs:   None.
  610.  
  611. Include:   Stdlib.a
  612.  
  613.      Like PutISize above, except this guy prints the long integer value in
  614. DX:AX.  Note that there may be as many as 11 print positions (e.g.,
  615. -1,000,000,000).
  616.  
  617.      Example:
  618.  
  619.                      mov     cx, 16
  620.                      mov     dx, word ptr L+2
  621.                      mov     ax, word ptr L
  622.                      PutLSize
  623.  
  624.  
  625. 2.19 PutULSize
  626.  
  627. *          Prints the value in DX:AX as a long unsigned decimal integer.
  628.  
  629. *          Prints the number in a minimum field width specified by the value in
  630.            CX.
  631.  
  632. Inputs:    DX:AX- Value to print.
  633.            CX- Minimum number of print positions to use.
  634.  
  635. Outputs:   None.
  636.  
  637. Include:   Stdlib.a
  638.  
  639.      Just like PutLSize above except this guy prints unsigned numbers rather
  640. than signed long integers.  The largest field width for such a value is 10
  641. print positions.
  642.  
  643.      Example:
  644.  
  645.                      mov     cx, 8
  646.                      mov     dx, word ptr UL+2
  647.                      mov     ax, word ptr UL
  648.                      PutULSize
  649.  
  650.  
  651. 2.20 Print
  652.  
  653. *          Prints a string literal.
  654.  
  655. *          Very convenient to use.
  656.  
  657. *          Calls stdlib putc routine to print characters to the stdlib standard
  658.            output device.
  659.  
  660. Inputs:    CS:RET - Return address points at the string to print.
  661.  
  662. Outputs:   None.
  663.  
  664. Include:   Stdlib.a
  665.  
  666.      Print lets you print string literals in a convenient fashion.  The string
  667. to print immediately follows the call to the print routine.  The string must
  668. contain a zero terminating byte and may not contain any intervening zero
  669. bytes.  Since the print routine returns to the address immediately following
  670. the zero terminating byte, forgetting this byte or attempting to print a zero
  671. byte in the middle of a literal string will cause print to return to an
  672. unexpected instruction.  This usually hangs up the machine.  Be very careful
  673. when using this routine!
  674.  
  675.      Example:
  676.  
  677.                      print
  678.                      db      "Print this string to the display device"
  679.                      db      13,10
  680.                      db      "This appears on a new line"
  681.                      db      13,10
  682.                      db      0
  683.  
  684.  
  685. 2.21 Printf
  686.  
  687. *          Formatted output routine.
  688.  
  689. *          Very similar to the "C" function of the same name.
  690.  
  691. *          Prints integers (normal, long, unsigned, etc.), characters, strings,
  692.            and other data types (this routine, however, does not support
  693.            floating point output).
  694.  
  695. *          Calls stdlib putc routine to print characters to the stdlib standard
  696.            output device.
  697.  
  698. Inputs:    CS:RET - Return address points at the format string.
  699.  
  700. Outputs:   None.
  701.  
  702. Include:   Stdlib.a
  703.  
  704.      Printf, like its "C" namesake, provides formatted output capabilities for
  705. the stdlib package.  A typical call to printf always takes the following form:
  706.  
  707.                     printf
  708.                     db        "format string",0
  709.                     dd        operand1, operand2, ..., operandn
  710.  
  711. The format string is comparable to the one provided in the "C" programming
  712. language.  For most characters, printf simply prints the characters in the
  713. format string up to the terminating zero byte.  The two exceptions are
  714. character prefixed by a backslash ("\") and character prefixed by a percent
  715. sign ("%").  Like C's printf, stdlib's printf uses the backslash as an escape
  716. character and the percent sign as a lead-in to a format string.
  717.  
  718.      Printf uses the escape character ("\") to print special characters in a
  719. fashion similar to, but not identical to C's printf.  Stdlib's printf routine
  720. supports the following special characters:
  721.  
  722. *       r       Print a carriage return (but no line feed)
  723.  
  724. *       n       Print a new line character (carriage return/line feed).
  725.  
  726. *       b       Print a backspace character.
  727.  
  728. *       t       Print a tab character.
  729.  
  730. *       l       Print a line feed character (but no carriage return).
  731.  
  732. *       f       Print a form feed character.
  733.  
  734. *       \       Print the backslash character.
  735.  
  736. *       %       Print the percent sign character.
  737.  
  738. *       0xhh    Print ASCII code hh, represented by two hex digits.
  739.  
  740.  
  741.      C users should note a couple of differences between stdlib's escape
  742. sequences and C's.  First, use "\%" to print a percent sign within a format
  743. string, not "%%".  C doesn't allow the use of "\%" because the C compiler
  744. processes "\%" at compile time (leaving a single "%" in the object code)
  745. whereas printf processes the format string at run-time.  It would see a single
  746. "%" and treat it as a format lead-in character.  Stdlib's printf, on the other
  747. hand, processes both the "\" and "%" and run-time, therefore it can distinguish
  748. "\%".
  749.  
  750.      Strings of the form "\0xhh" must contain exactly two hex digits.  The
  751. current printf routine isn't robust enough to handle sequences of the form
  752. "\0xh" which contain only a single hex digit.  Keep this in mind if you find
  753. printf chopping off characters after you print a value.
  754.  
  755.      There is absolutely no reason to use any escape character sequences except
  756. "\0x00".  Printf grabs all characters following the call to printf up to the
  757. terminating zero byte (which is why you'd need to use "\0x00" if you want to
  758. print the null character, printf will not print such values).  Stdlib's printf
  759. routine doesn't care how those characters got there.  In particular, you are
  760. not limited to using a single string after the printf call.  The following is
  761. perfectly legal:
  762.  
  763.                      printf
  764.                      db      "This is a string",13,10
  765.                      db      "This is on a new line",13,10
  766.                      db      "Print a backspace at the end of this line:"
  767.                      db      8,13,10,0
  768.  
  769.      You code will run a tiny amount faster if you avoid the use of the escape
  770. character sequences.  More importantly, the escape character sequences take at
  771. least two bytes.  You can encode most of them as a single byte by simply
  772. embedding the ASCII code for that byte directly into the code stream.  Don't
  773. forget, you cannot embed a zero byte into the code stream.  A zero byte
  774. terminates the format string.  Instead, use the "\0x00" escape sequence.
  775.  
  776.      Format sequences always between with "%".  For each format sequence you
  777. must provide a far pointer to the associated data immediately following the
  778. format string, e.g.,
  779.  
  780.                      printf
  781.                      db      "%i %i",0
  782.                      dd      i,j
  783.  
  784.      Format sequences take the general form "%s\cn^f" where:
  785.  
  786.      *    "%" is always the "%" character.  Use "\%" if you actually want
  787.           to print a percent sign.
  788.  
  789.      *    s is either nothing or a minus sign ("-").
  790.  
  791.      *    "\c" is also optional, it may or may not appear in the format
  792.           item.  "c" represents any printable character.
  793.  
  794.      *    "n" represents a string of 1 or more decimal digits.
  795.  
  796.      *    "^" is just the caret (up-arrow) character.
  797.  
  798.      *    "f" represents one of the format characters: i, d, x, h, u, c,
  799.           s, ld, li, lx, or lu.
  800.  
  801.      The "s", "\c", "n", and "^" items are optional, the "%" and "f" items must
  802. be present.  Furthermore, the order of these items in the format item is very
  803. important.  The "\c" entry, for example, cannot precede the "s" entry.
  804. Likewise, the "^" character, if present, must follow everything except the "f"
  805. character(s).
  806.  
  807.      The format characters i, d, x, h, u, c, s, ld, li, lx, and lu control the
  808. output format for the data.  The i and d format characters perform identical
  809. functions, they tell printf to print the following value as a 16-bit signed
  810. decimal integer.  The x and h format characters instruct printf to print the
  811. specified value as a 16-bit or 8-bit hexadecimal value (respectively).  If you
  812. specify u, printf prints the value as a 16-bit unsigned decimal integer.  Using
  813. c tells printf to print the value as a single character.  S tells printf that
  814. you're supplying the address of a zero-terminated character string, printf
  815. prints that string.  The ld, li, lx, and lu entries are long (32-bit) versions
  816. of d/i, x, and u.  The corresponding address points at a 32-bit value which
  817. printf will format and print to the standard output.  The following example
  818. demonstrates these format items:
  819.  
  820.                      printf
  821.                      db      "I= %i, U= %u, HexC= %h, HexI= %x, C= %c, "
  822.                      db      "S= %s",13,10
  823.                      db      "L= %ld",13,10,0
  824.                      dd      i,u,c,i,c,s,l
  825.  
  826.      The number of far addresses (specified by operands to the "dd"
  827. pseudo-opcode) must match the number of "%" format items in the format string.
  828. Printf counts the number of "%" format items in the format string and skips
  829. over this many far addresses following the format string.  If the number of
  830. items do not match, the return address for printf will be incorrect and the
  831. program will probably hang or otherwise malfunction.  Likewise (as for the
  832. print routine), the format string must end with a zero byte.  The addresses of
  833. the items following the format string must point directly at the memory
  834. locations where the specified data lies.
  835.  
  836.      When used in the format above, printf always prints the values using the
  837. minimum number of print positions for each operand.  If you want to specify a
  838. minimum field width, you can do so using the "n" format option.  A format item
  839. of the format "%10d" prints a decimal integer using at least ten print
  840. positions.  Likewise, "%16s" prints a string using at least 16 print
  841. positions.  If the value to print requires more than the specified number of
  842. print positions, printf will use however many are necessary.  If the value to
  843. print requires fewer, printf will always print the specified number, padding
  844. the value with blanks.  Printf will print the value right justified in the
  845. print field (regardless of the data's type).  If you want to print the value
  846. left justified in the output file, use the "-" format character as a prefix to
  847. the field width, e.g.,
  848.  
  849.                      printf
  850.                      db      "%-17s",0
  851.                      dd      string
  852.  
  853. In this example, printf prints the string using a 17 character long field with
  854. the string left justified in the output field.
  855.  
  856.      By default, printf blank fills the output field if the value to print
  857. requires fewer print positions than specified by the format item.  The "\c"
  858. format item allows you to change the padding character.  For example, to print
  859. a value, right justified, using "*" as the padding character you would use the
  860. format item "%\*10d".  To print it left justified you would use the format item
  861. "%-\*10d".  Note that the "-" must precede the "\*".  This is a limitation of
  862. the current version of the software.  The operands must appear in this order.
  863.  
  864.      Normally, the address(es) following the printf format string must be far
  865. pointers to the actual data to print.  On occassion, especially when allocating
  866. storage on the heap (using malloc), you may not know (at assembly time) the
  867. address of the object you want to print.  You may have only a pointer to the
  868. data you want to print.  The "^" format option tells printf that the far
  869. pointer following the format string is the address of a pointer to the data
  870. rather than the address of the data itself.  This option lets you access the
  871. data indirectly.
  872.  
  873.      Examples:
  874.  
  875.                      printf
  876.                      db      "Indirect access to i: %^d",13,10,0
  877.                      dd      IPtr
  878.      ;
  879.                      printf
  880.                      db      "A string allocated on the heap: %-\.32^s"
  881.                      db      13,10,0
  882.                      dd      SPtr
  883.  
  884.  
  885.      Note: unlike C, stdlib's printf routine does not support floating point
  886. output.  There are two reasons for this: first, stdlib does not (yet) have a
  887. floating point library associated with it; second, adding floating point
  888. support would increase the size of printf by a tremendous amount, even if you
  889. don't use its floating point capabilities.  Since most assembly language
  890. programmers don't use floating point arithmetic, I've intentionally left out
  891. floating point output.  As soon as I add a floating point package to stdlib I
  892. will include floating point output.  However, I will create a new routine,
  893. printff which includes floating point output.  This will allow those who never
  894. use floating point I/O to keep their programs much smaller.
  895.  
  896.  
  897. 3 Character Input Routines
  898.  
  899.  
  900.  
  901. 3.1 Getc
  902.  
  903. *          Reads a character from the standard input device and returns the
  904.            character in the AL register.
  905.  
  906. *          Redirectable under program control.
  907.  
  908. Inputs:    None.
  909.  
  910. Outputs:   AL- Character from input device.
  911.            AH- Undefined.  However, if AL contains zero, AH should contain a
  912.            keyboard scan code.
  913.  
  914. Include:   Stdlib.a
  915.  
  916.      This routine reads a character from the standard input device.  This call
  917. is synchronous, that is, it does not return until a character is available.
  918. Default input device is DOS standard input.
  919.  
  920.      Example:
  921.  
  922.                      getc
  923.                      mov     KbdChar, al
  924.                      putc
  925.  
  926.  
  927. 3.2 GetcStdIn
  928.  
  929. *          Reads a character from the DOS standard input device and returns the
  930.            character in the AL register.
  931.  
  932. *          Redirectable from DOS command line.
  933.  
  934. Inputs:    None.
  935.  
  936. Outputs:   AL- Character from input device.
  937.            AH- Scan code if AL=0.
  938.  
  939. Include:   Stdlib.a
  940.  
  941.      This routine reads a character from the DOS standard input device.  This
  942. call is synchronous, that is, it does not return until a character is
  943. available.
  944.  
  945.      Example:
  946.  
  947.                      GetcStdIn
  948.                      mov     InputChr, al
  949.                      putc
  950.  
  951.  
  952. 3.3 GetcBIOS
  953.  
  954. *          Reads a character from the keyboard and returns the character in the
  955.            AL register and the scan code in the AH register.
  956.  
  957. Inputs:    None.
  958.  
  959. Outputs:   AL- Character from the keyboard.
  960.            AH- Scan code from the keyboard.
  961.  
  962. Include:   Stdlib.a
  963.  
  964.      This routine reads a character from the keyboard.  This call is
  965. synchronous, that is, it does not return until a character is available.
  966.  
  967.      Example:
  968.  
  969.                      GetcBIOS
  970.                      mov     CharRead, al
  971.                      mov     ScanCode, ah
  972.                      putc
  973.  
  974.  
  975. 3.4 SetInAdrs
  976.  
  977. *          Lets you set the address of the current input routine.
  978.  
  979. Inputs:    es:di- Address of new input routine.
  980.  
  981. Outputs:   None.
  982.  
  983. Include:   stdlib.a
  984.  
  985.      This routine redirects the stdlib standard input so that it calls the
  986. routine whose address you pass in es:di.  This routine should obtain a
  987. character (from anywhere) and return the character in AL.  If it makes sense do
  988. do so, it should also return a "scan code" in the AH register.  It must
  989. preserve all other registers.
  990.  
  991.      Example:
  992.  
  993.                      mov     es, seg NewInputRoutine
  994.                      mov     di, offset NewInputRoutine
  995.                      SetInAdrs
  996.                         .
  997.                         .
  998.                         .
  999.                      les     di, RoutinePtr
  1000.                      SetInAdrs
  1001.  
  1002.  
  1003. 3.5 GetInAdrs
  1004.  
  1005. *          Retrieves address of the current input routine.
  1006.  
  1007. Inputs:    None.
  1008.  
  1009. Outputs:   es:di - address of current input routine (called by Getc).
  1010.  
  1011. Include:   stdlib.a
  1012.  
  1013.      You can use this function to get the address of the current input routine,
  1014. perhaps so you can save it or see if it is currently pointing at some
  1015. particular piece of code.  If you want to temporarily redirect the input and
  1016. then restore the original input routine, consider using PushInAdrs/PopInAdrs
  1017. described later.
  1018.  
  1019.      Example:
  1020.  
  1021.                      GetInAdrs
  1022.                      mov     word ptr SaveInAdrs, di
  1023.                      mov     word ptr SaveInAdrs+2, es
  1024.  
  1025.  
  1026. 3.6 PushInAdrs
  1027.  
  1028. *          Lets you redirect the standard input device and preserve the
  1029.            previous address.
  1030.  
  1031. *          Saves up to 16 old input routine addresses on an internal stack.
  1032.  
  1033. *          Restoration is possible using PopInAdrs.
  1034.  
  1035. Inputs:    es:di- Address of new input routine.
  1036.  
  1037. Outputs:   Carry=0 if operation successful.
  1038.            Carry=1 if there were already 16 items on the stack.
  1039.  
  1040. Include:   stdlib.a
  1041.  
  1042.      This routine "pushes" the current input address onto an internal stack and
  1043. then stores the value in es:di into the current input routine pointer.  The
  1044. PushInAdrs and PopInAdrs routines let you easily save and redirect the standard
  1045. output and then restore the original output routine address later on.
  1046.  
  1047.      If you attempt to push more than 16 items on the stack, PushInAdrs will
  1048. ignore your request and return with the carry flag set.  If PushInAdrs is
  1049. successful, it will return with the carry flag clear.
  1050.  
  1051.      Example:
  1052.  
  1053.                      mov     es, seg NewInputRoutine
  1054.                      mov     di, offset NewInputRoutine
  1055.                      PushInAdrs
  1056.                         .
  1057.                         .
  1058.                         .
  1059.                      les     di, RoutinePtr
  1060.                      PushInAdrs
  1061.  
  1062.  
  1063. 3.7 PopInAdrs
  1064.  
  1065. *          Restores output routine addresses saved by PushInAdrs.
  1066.  
  1067. *          Defaults to GetcStdOut if you attempt to pop too many items off the
  1068.            stack.
  1069.  
  1070. Inputs:    None.
  1071.  
  1072. Outputs:   es:di- Points at the previous stdout routine before the pop.
  1073.  
  1074. Include:   stdlib.a
  1075.  
  1076.      PopInAdrs undoes the effects of PushInAdrs.  It pops an item off the
  1077. internal stack and stores it into the input routine pointer.  The previous
  1078. value in the output pointer is returned in es:di.
  1079.  
  1080.      Example:
  1081.  
  1082.                      mov     es, seg NewInRoutine
  1083.                      mov     di, offset NewInputRoutine
  1084.                      PushInAdrs
  1085.                         .
  1086.                         .
  1087.                         .
  1088.                      PopInAdrs
  1089.  
  1090.  
  1091. 3.8 Gets
  1092.  
  1093. *          Reads a line of text from the stdlib standard input device.
  1094.  
  1095. *          Automatically allocates storage for the input string on the heap.
  1096.  
  1097. *          Handles input lines up to 256 characters long.
  1098.  
  1099. Inputs:    None.
  1100.  
  1101. Outputs:   es:di - address of input of text.
  1102.  
  1103. Include:   stdlib.a
  1104.  
  1105.      Gets reads a line of text from the stdlib standard input.  It returns a
  1106. pointer to a string containing each character read in the ES:DI registers.
  1107. Gets calls malloc to allocate 256 bytes on the heap (plus any overhead bytes
  1108. required by the memory manager system).  If the user enters less than 256
  1109. bytes, gets calls realloc to free any unnecessary bytes.  Gets returns all
  1110. characters typed by the user except for the carriage return (ENTER) key code.
  1111. Gets always returns a zero-terminated string.  The action of various keys to
  1112. gets depends upon where input has be directed.  Generally, you can count on
  1113. gets properly handling the backspace (erase previous character), escape (erase
  1114. entire line), and ENTER (accept line) keys.  Other keys may be active as well.
  1115. For example, by default gets calls getc which calls DOS' standard input
  1116. routine.  If you type a control-C or break key while reading from DOS' standard
  1117. input it will abort the program.  If this bothers you, you can always redirect
  1118. stdlib's getc routine so it calls BIOS directly rather than reading data
  1119. through DOS' keyboard input routine.
  1120.  
  1121.      Example:
  1122.  
  1123.                      gets            ;Read a string from the keyboard
  1124.                      puts            ;Print it
  1125.                      putcr           ;Print a new line
  1126.                      free            ;Deallocate storage for string.
  1127.  
  1128.  
  1129. 3.9 Scanf
  1130.  
  1131. *          Formatted input from stdlib standard input.
  1132.  
  1133. *          Similar to C's scanf routine.
  1134.  
  1135. *          Converts ASCII to integer, unsigned, character, string, hex, and
  1136.            long values of the above.
  1137.  
  1138. Inputs:    None.
  1139.  
  1140. Outputs:   None.
  1141.  
  1142. Include:   stdlib.a
  1143.  
  1144.      Scanf provides formatted input in a fashion analogous to printf's output
  1145. facilities.  Actually, it turns out that scanf is considerably less useful than
  1146. printf because it doesn't provide reasonable error checking facilities (neither
  1147. does C's version of this routine).  But for quick and dirty programs whose
  1148. input can be controlled in a rigid fashion (or if you're willing to live by
  1149. "garbage in, garbage out")  scanf provides a convenient way to get input from
  1150. the user.
  1151.  
  1152.      Like printf, the scanf routine expects you to follow the call with a
  1153. format string and then a list of (far pointer) memory addresses.  The items in
  1154. the scanf format string take the following form:
  1155.  
  1156.                     %^f
  1157.  
  1158. where f represents d, i, x, h, u, c, x, ld, li, lx, or lu.  Like printf, the
  1159. "^" symbol tells scanf that the address following the format string is the
  1160. address of a (far) pointer to the data rather than the address of the data
  1161. location itself.
  1162.  
  1163.      By default, scanf automatically skips any leading whitespace before
  1164. attempting to read a numeric value.  You can instruct scanf to skip other
  1165. characters by placing that character in the format string.  For example, the
  1166. following call instructs scanf to read three integers separated by commas
  1167. (and/or whitespace):
  1168.  
  1169.                      scanf
  1170.                      db      "%i,%i,%i",0
  1171.                      dd      i1,i2,i3
  1172.  
  1173.      Whenever scanf encounters a non-blank character in the format string, it
  1174. will skip that character (including multiple occurrences of that character) if
  1175. it appears next in the input stream.
  1176.  
  1177.      Scanf always calls gets to read a new line of text from stdlib's standard
  1178. input.  If scanf exhausts the format list, it ignores any remaining characters
  1179. on the line.  If scanf exhausts the input line before processing all of the
  1180. format items, it leaves the remaining variables unchanged.  Scanf always
  1181. deallocates the storage allocated by gets.
  1182.  
  1183.      Example:
  1184.  
  1185.                      scanf
  1186.                      db      "%i  %h  %^s",0
  1187.                      dd      i, x, sptr
  1188.  
  1189.  
  1190. 4 Conversion Routines
  1191.  
  1192.  
  1193.  
  1194. 4.1 ATOL/ATOL2
  1195.  
  1196. *          Converts an ASCII string of digits to long integer format.
  1197.  
  1198. Inputs:    ES:DI- Points at string to convert.
  1199.  
  1200. Outputs:   DX:AX- Long integer converted from string.
  1201.            Carry flag- Error status
  1202.            DI (ATOL2)- First character beyond string of digits.
  1203.  
  1204. Include:   stdlib.a
  1205.  
  1206.      ATOL convert the string of digits that ES:DI points at to a long integer
  1207. (signed) value and returns this value in DX:AX.  ATOL2 works in a similar
  1208. fashion except it doesn't preserve the DI register.  That is, it leaves DI
  1209. pointing at the first character beyond the string of digits.  This routine
  1210. returns the carry flag clear if it translated the string of digits witout
  1211. error.  It returns the carry flag set if overflow occurred.  Note that this
  1212. routine stops on the first non-digit.  If the string does not begin with a
  1213. digit, this routine returns zero.  The only except to the "string of digits"
  1214. rule is that the number can have a preceding minus sign to denote a negative
  1215. number.  In particular, note that this routine does not allow leading spaces.
  1216.  
  1217.      Example:
  1218.  
  1219.                      gets            ;Get a string from user
  1220.                      atol            ;Convert to a value in DX:AX
  1221.  
  1222.  
  1223. 4.2 ATOUL/ATOUL2
  1224.  
  1225.      Just like ATOL above, except this guy handles unsigned long integers.
  1226.  
  1227.  
  1228. 4.3 ATOI
  1229.  
  1230. *          Converts an ASCII string of digits to integer format.
  1231.  
  1232. Inputs:    ES:DI- Points at string to convert.
  1233.  
  1234. Outputs:   AX- Integer converted from string.
  1235.            Carry flag- Error status
  1236.            DI (ATOI2)- First character beyond string of digits.
  1237.  
  1238. Include:   stdlib.a
  1239.  
  1240.      Works just like ATOL except it translates the string to a signed 16-bit
  1241. integer rather than a 32-bit long integer.
  1242.  
  1243.  
  1244. 4.4 ATOU/ATOU2
  1245.  
  1246. *          Converts an ASCII string of digits to unsigned integer format.
  1247.  
  1248. Inputs:    ES:DI- Points at string to convert.
  1249.  
  1250. Outputs:   AX- Unsigned 16-bit integer converted from string.
  1251.            Carry flag- Error status
  1252.            DI (ATOU2)- First character beyond string of digits.
  1253.  
  1254. Include:   stdlib.a
  1255.  
  1256.      Like ATOI except it handle unsigned 16-bit integers in the range 0..65535.
  1257.  
  1258.  
  1259. 4.5 ATOH/ATOH2
  1260.  
  1261. *          Converts an ASCII string of hex digits to a value in AX.
  1262.  
  1263. Inputs:    ES:DI- Points at string to convert.
  1264.  
  1265. Outputs:   AX- Unsigned 16-bit integer converted from hex string.
  1266.            Carry flag- Error status
  1267.            DI (ATOH2)- First character beyond string of hex digits.
  1268.  
  1269. Include:   stdlib.a
  1270.  
  1271.      This routine converts a string of hexadecimal digits into numeric form and
  1272. returns that value in the AX register.
  1273.  
  1274.      Example:
  1275.  
  1276.                      les     di, Str2Convrt
  1277.                      atoh                    ;Convert to value in AX.
  1278.                      putw                    ;Print word in AX.
  1279.  
  1280.  
  1281. 4.6 ATOLH/ATOLH2
  1282.  
  1283.      Like ATOH above, except it handles 32-bit values and returns the result in
  1284. DX:AX.
  1285.  
  1286.  
  1287. 4.7 ITOA
  1288.  
  1289. *          Converts a 16-bit signed integer value in AX to a string of
  1290.            characters.
  1291.  
  1292. *          Automatically allocates storage for string on the heap.
  1293.  
  1294. Inputs:    AX- Signed 16-bit value to convert to a string.
  1295.  
  1296. Outputs:   ES:DI- Pointer to string containing converted characters.
  1297.  
  1298. Include:   stdlib.a
  1299.  
  1300.      ITOA converts the signed integer value in AX to a string of characters
  1301. which represent that value.  It allocates storage for this string on the heap
  1302. via a call to the malloc routine and returns a pointer to that string in
  1303. ES:DI.  The string contains the minimum number of characters required to hold
  1304. the character representation of the value and is always between one and six
  1305. characters long.
  1306.  
  1307.      Example:
  1308.  
  1309.                      mov     ax, -1234
  1310.                      itoa                    ;Convert to string.
  1311.                      puts                    ;Print it.
  1312.                      free                    ;Deallocate string.
  1313.  
  1314.  
  1315. 4.8 UTOA
  1316.  
  1317. *          Converts a 16-bit unsigned integer value in AX to a string of
  1318.            characters.
  1319.  
  1320. *          Automatically allocates storage for string on the heap.
  1321.  
  1322. Inputs:    AX- Unsigned 16-bit value to convert to a string.
  1323.  
  1324. Outputs:   ES:DI- Pointer to string containing converted characters.
  1325.  
  1326. Include:   stdlib.a
  1327.  
  1328.      Like ITOA above, except it converts the unsigned value in AX to a string
  1329. of characters.  The string returned by UTOA is always one to five characters
  1330. long.
  1331.  
  1332.      Example:
  1333.  
  1334.                      mov     ax, 65000
  1335.                      utoa
  1336.                      puts
  1337.                      free
  1338.  
  1339.  
  1340. 4.9 HTOA
  1341.  
  1342. *          Converts an 8-bit value in AL to the two-character hexadecimal
  1343.            representation of that byte.
  1344.  
  1345. *          Automatically allocates storage for string on the heap.
  1346.  
  1347. Inputs:    AL- 8-bit value to convert to a string.
  1348.  
  1349. Outputs:   ES:DI- Pointer to string containing converted characters.
  1350.  
  1351. Include:   stdlib.a
  1352.  
  1353.      Converts a byte to a string containing the hexadecimal representation of
  1354. that byte.  Otherwise, it's just like ITOA above.  This routine always outputs
  1355. exactly two hexadecimal digits, including a leading zero (if necessary).
  1356.  
  1357.  
  1358.  
  1359. 4.10 WTOA
  1360.  
  1361. *          Converts a 16-bit value in AX to hexadecimal representation.
  1362.  
  1363. *          Automatically allocates storage for string on the heap.
  1364.  
  1365. Inputs:    AX- 16-bit value to convert to a string.
  1366.  
  1367. Outputs:   ES:DI- Pointer to string containing converted characters.
  1368.  
  1369. Include:   stdlib.a
  1370.  
  1371.      Like HTOA above, except it converts the 16-bit value in AX to a string of
  1372. four hexadecimal digits.  Outputs exactly four digits including leading zeros
  1373. if necessary.
  1374.  
  1375.  
  1376. 4.11 LTOA
  1377.  
  1378. *          Converts a 32-bit signed integer value in DX:AX to a string of
  1379.            characters.
  1380.  
  1381. *          Automatically allocates storage for string on the heap.
  1382.  
  1383. Inputs:    DX:AX- Signed 32-bit value to convert to a string.
  1384.  
  1385. Outputs:   ES:DI- Pointer to string containing converted characters.
  1386.  
  1387. Include:   stdlib.a
  1388.  
  1389.      Like ITOA except it converts a long integer value in DX:AX to a string of
  1390. one to eleven characters.
  1391.  
  1392.  
  1393. 4.12 ULTOA
  1394.  
  1395. *          Converts a 32-bit unsigned integer value in DX:AX to a string of
  1396.            characters.
  1397.  
  1398. *          Automatically allocates storage for string on the heap.
  1399.  
  1400. Inputs:    DX:AX- Unsigned 32-bit value to convert to a string.
  1401.  
  1402. Outputs:   ES:DI- Pointer to string containing converted characters.
  1403.  
  1404. Include:   stdlib.a
  1405.  
  1406.      Like LTOA except this guy handles unsigned integer values.
  1407.  
  1408.  
  1409. 4.13 SPrintf
  1410.  
  1411. *          In-memory formatting routine.
  1412.  
  1413. *          Just like C's sprintf routine.
  1414.  
  1415. *          Automatically allocates storage for the string on the heap.
  1416.  
  1417. *          Programmer selectable maximum length for the output string.
  1418.  
  1419. Inputs:    CS:RET- Pointer to format string and operands of the sprintf
  1420.            routine.
  1421.  
  1422. Outputs:   ES:DI- Pointer to string containing output data.
  1423.  
  1424. Include:   stdlib.a
  1425.  
  1426.      Works in a manner quite similar to printf except sprintf writes its output
  1427. to a string variable rather than to the stdlib standard output.  Sprintf
  1428. returns a pointer to the string (which is allocates on the heap) in the ES:DI
  1429. registers.  SPrintf, by default, allocates 2048 characters for this string and
  1430. then deallocates any unnecessary storage.  An external variable, sp_MaxBuf,
  1431. holds the number of bytes to allocate upon entry into sprintf.  If you wish to
  1432. allocate more or less than 2048 bytes when calling sprintf, simply change the
  1433. value of this public variable (type is word).  Sprintf calls malloc to allocate
  1434. the storage dynamically.  You should call free to return this buffer to the
  1435. heap when you are through with it.
  1436.  
  1437.  
  1438.      Example:
  1439.  
  1440.                      sprintf
  1441.                      db      "I=%i, U=%u, S=%s",13,10,0
  1442.                      db      i,u,s
  1443.                      puts
  1444.                      free
  1445.  
  1446.  
  1447. 4.14 SBPrintf
  1448.  
  1449. *          In-memory formatting routine.
  1450.  
  1451. *          Programmer-supplied output buffer for string
  1452.  
  1453. Inputs:    CS:RET- Pointer to format string and operands of the sprintf
  1454.            routine.
  1455.            ES:DI- Pointer to buffer area to store string data.
  1456.  
  1457. Outputs:   None.
  1458.  
  1459. Include:   stdlib.a
  1460.  
  1461.      Works just like sprintf except it does not automatically allocate storage
  1462. for the output string.  Instead, you must supply the address of an output
  1463. buffer in the ES:DI registers.
  1464.  
  1465.      Example:
  1466.  
  1467.                      les     di, BufferAdrs
  1468.                      sbprintf
  1469.                      db      "I=%i, U=%u, S=%s",13,10,0
  1470.                      db      i,u,s
  1471.                      puts
  1472.  
  1473.  
  1474. 4.15 SScanf
  1475.  
  1476. *          Formatted in-memory conversions.
  1477.  
  1478. *          Similar to C's sscanf routine.
  1479.  
  1480. *          Converts ASCII to integer, unsigned, character, string, hex, and
  1481.            long values of the above.
  1482.  
  1483. Inputs:    ES:DI- Points at string containing values to convert.
  1484.            CS:RET- Points at format string and variable parameter list.
  1485.  
  1486. Outputs:   None.
  1487.  
  1488. Include:   stdlib.a
  1489.  
  1490.      Sscanf provides formatted input in a fashion analogous to scanf.  The
  1491. difference is that scanf reads a line of text from the stdlib standard input
  1492. whereas you pass the address of a sequence of characters to sscanf in es:di.
  1493.  
  1494.      Example:
  1495.  
  1496.      ;
  1497.      ; This code reads the values for i, j, and s from the characters
  1498.      ; starting at memory locaiton Buffer.
  1499.      ;
  1500.                      les     di, Buffer
  1501.                      sscanf
  1502.                      db      "%i %i %s",0
  1503.                      dd      i,j,s
  1504.  
  1505.  
  1506. 4.16 ToLower
  1507.  
  1508. *          Converts uppercase characters in AL to lower case.
  1509.  
  1510. *          Macro implementation for high performance.
  1511.  
  1512. *          Leaves characters other than uppercase unchanged.
  1513.  
  1514. Inputs:    AL- Character to (possibly) convert to lower case.
  1515.  
  1516. Outputs:   AL- Converted character.
  1517.  
  1518. Include:   stdlib.a
  1519.  
  1520.      ToLower checks the character in the AL register.  If it is upper case it
  1521. converts it to lower case.  If it is anything else, ToLower leaves the value in
  1522. AL unchanged.  Note: this routine is implemented as a macro rather than as a
  1523. procedure call.  This routine is so short you would spend more time actually
  1524. calling the routine than executing the code inside.  However, the code is
  1525. definitely longer than a (far) procedure call, so if space is critical and
  1526. you're invoking this code several times, you may want to convert it to a
  1527. procedure call to save a little space.
  1528.  
  1529.      Example:
  1530.  
  1531.                      mov     al, char
  1532.                      ToLower
  1533.  
  1534.  
  1535. 4.17 ToUpper
  1536.  
  1537. *          Converts lowercase characters in AL to upper case.
  1538.  
  1539. *          Macro implementation for high performance.
  1540.  
  1541. *          Leaves characters other than lowercase unchanged.
  1542.  
  1543. Inputs:    AL- Character to (possibly) convert to upper case.
  1544.  
  1545. Outputs:   AL- Converted character.
  1546.  
  1547. Include:   stdlib.a
  1548.  
  1549.      This is just like the ToLower routine except it converts lower case to
  1550. uppercase rather than vice versa.
  1551.  
  1552.  
  1553. 5 Utility Routines
  1554.  
  1555.  
  1556.  
  1557. 5.1 ISize
  1558.  
  1559. *          Computes the number of print positions required by a 16-bit signed
  1560.            integer value.
  1561.  
  1562. Inputs:    AX- 16-bit value to compute the output size for.
  1563.  
  1564. Outputs:   AX- Number of print positions required by this number (including the
  1565.            minus sign, if necessary).
  1566.  
  1567. Include:   stdlib.a
  1568.  
  1569.      ISize computes the minimum number of character positions it will take to
  1570. print the signed decimal value in the AX register.  If the number is negative,
  1571. it will include space for the minus sign in the count.
  1572.  
  1573.      Example:
  1574.  
  1575.                      mov     ax, I
  1576.                      ISize
  1577.                      puti                    ;Prints positions req'd by I.
  1578.  
  1579.  
  1580. 5.2 USize
  1581.  
  1582.      Just like ISize above, except this guy returns the number of print
  1583. positions required by a 16-bit unsigned value.
  1584.  
  1585.  
  1586. 5.3 LSize
  1587.  
  1588. *          Computes the number of print positions required by a 32-bit signed
  1589.            integer value.
  1590.  
  1591. Inputs:    DX:AX- 32-bit value to compute the output size for.
  1592.  
  1593. Outputs:   AX- Number of print positions required by this number (including the
  1594.            minus sign, if necessary).
  1595.  
  1596. Include:   stdlib.a
  1597.  
  1598.      LSize computes the minimum number of character positions it will take to
  1599. print the signed decimal value in the DX:AX registers.  If the number is
  1600. negative, it will include space for the minus sign in the count.
  1601.  
  1602.      Example:
  1603.  
  1604.                      mov     ax, word ptr L
  1605.                      mov     dx, word ptr L+2
  1606.                      LSize
  1607.                      puti                    ;Prints positions req'd by L.
  1608.  
  1609.  
  1610. 5.4 ULSize
  1611.  
  1612.      As with LSize, except ULSize treats the value in DX:AX as an unsigned long
  1613. integer.
  1614.  
  1615.  
  1616. 5.5 IsAlNum
  1617.  
  1618. *          Checks character in AL to see if it is alphanumeric.
  1619.  
  1620. Inputs:    AL- Character to check.
  1621.  
  1622. Outputs:   Zero flag- Set if character is alphanumeric, clear if not.
  1623.  
  1624. Include:   stdlib.a
  1625.  
  1626.      This procedure checks the character in the AL register to see if it is in
  1627. the range A-Z, a-z, or 0-9.  Upon return, you can use the JE instruction to
  1628. check to see if the character was in this range (or, conversely, you can use
  1629. jne to see if it is not in the range).
  1630.  
  1631.      Example:
  1632.  
  1633.                      mov     al, char
  1634.                      IsAlNum
  1635.                      je      IsAlNumChar
  1636.  
  1637.  
  1638. 5.6 IsXDigit
  1639.  
  1640. *          Checks character in AL to see if it is a hexadecimal digit.
  1641.  
  1642. Inputs:    AL- Character to check.
  1643.  
  1644. Outputs:   Zero flag- Set if character is a hex digit, clear if not.
  1645.  
  1646. Include:   stdlib.a
  1647.  
  1648.      This procedure checks the character in the AL register to see if it is in
  1649. the range A-F, a-f, or 0-9.  Upon return, you can use the JE instruction to
  1650. check to see if the character was in this range (or, conversely, you can use
  1651. jne to see if it is not in the range).
  1652.  
  1653.      Example:
  1654.  
  1655.                      mov     al, char
  1656.                      IsXDigit
  1657.                      je      IsXDigitChar
  1658.  
  1659.  
  1660. 5.7 IsDigit
  1661.  
  1662. *          Checks character in AL to see if it is numeric.
  1663.  
  1664. *          Macro implementation for high performance.
  1665.  
  1666. Inputs:    AL- Character to check.
  1667.  
  1668. Outputs:   Zero flag- Set if character is numeric, clear if not.
  1669.  
  1670. Include:   stdlib.a
  1671.  
  1672.      This procedure checks the character in the AL register to see if it is in
  1673. the range 0-9.  Upon return, you can use the JE instruction to check to see if
  1674. the character was in this range (or, conversely, you can use jne to see if it
  1675. is not in the range).
  1676.  
  1677.      Example:
  1678.  
  1679.                      mov     al, char
  1680.                      IsDigit
  1681.                      je      IsDecChar
  1682.  
  1683.  
  1684. 5.8 IsAlpha
  1685.  
  1686. *          Checks character in AL to see if it is alphabetic.
  1687.  
  1688. *          Macro implementation for high performance.
  1689.  
  1690. Inputs:    AL- Character to check.
  1691.  
  1692. Outputs:   Zero flag- Set if character is alphabetic, clear if not.
  1693.  
  1694. Include:   stdlib.a
  1695.  
  1696.      This procedure checks the character in the AL register to see if it is in
  1697. the range A-Z, or a-z.  Upon return, you can use the JE instruction to check to
  1698. see if the character was in this range (or, conversely, you can use jne to see
  1699. if it is not in the range).
  1700.  
  1701.      Example:
  1702.  
  1703.                      mov     al, char
  1704.                      IsAlpha
  1705.                      je      IsAlChar
  1706.  
  1707.  
  1708. 5.9 IsLower
  1709.  
  1710. *          Checks character in AL to see if it is a lower case alphabetic
  1711.            character.
  1712.  
  1713. *          Macro implementation for high performance.
  1714.  
  1715. Inputs:    AL- Character to check.
  1716.  
  1717. Outputs:   Zero flag- Set if character is lower case alphabetic, clear if not.
  1718.  
  1719. Include:   stdlib.a
  1720.  
  1721.      This procedure checks the character in the AL register to see if it is in
  1722. the range a-z.  Upon return, you can use the JE instruction to check to see if
  1723. the character was in this range (or, conversely, you can use jne to see if it
  1724. is not in the range).
  1725.  
  1726.      Example:
  1727.  
  1728.                      mov     al, char
  1729.                      IsLower
  1730.                      je      IsLowerChar
  1731.  
  1732.  
  1733. 5.10 IsUpper
  1734.  
  1735. *          Checks character in AL to see if it is uppercase alphabetic.
  1736.  
  1737. *          Macro implementation for high performance.
  1738.  
  1739. Inputs:    AL- Character to check.
  1740.  
  1741. Outputs:   Zero flag- Set if character is uppercase alpha, clear if not.
  1742.  
  1743. Include:   stdlib.a
  1744.  
  1745.      This procedure checks the character in the AL register to see if it is in
  1746. the range A-Z.  Upon return, you can use the JE instruction to check to see if
  1747. the character was in this range (or, conversely, you can use jne to see if it
  1748. is not in the range).
  1749.  
  1750.      Example:
  1751.  
  1752.                      mov     al, char
  1753.                      IsUpper
  1754.                      je      IsUpperChar
  1755.  
  1756.  
  1757. 6 Memory Management
  1758.  
  1759.      The stdlib memory management routines let you dynamically allocate storage
  1760. on the heap.  These routines are somewhat similar to those provided by the "C"
  1761. programming language.  These routines do not perform garbage collection.  Doing
  1762. so would introduce too many restrictions.  Of course, feel free to add your own
  1763. garbage collection if you like...
  1764.  
  1765.      The allocation/deallocation routines should be fairly fast.  Malloc and
  1766. free use a modified first/next fit algorithm which lets the system quickly find
  1767. a memory block of the desired size without undue fragmentation problems
  1768. (average case).  The overhead (eight bytes) per allocated block may seem rather
  1769. high, but that is part of the price to pay for faster malloc and free routines.
  1770.  
  1771.      The memory manager data structure has an overhead of eight bytes (meaning
  1772. each malloc operation requires at least eight more bytes than you ask for) and
  1773. a granularity of 16 bytes.  All pointers are far pointers and I allocate each
  1774. new item on a paragraph boundary.  The current memory manager routines always
  1775. allocates (n+8) bytes, rounding up to the next multiple of 16 if the result is
  1776. not evenly divisible by sixteen.  The first eight bytes of the structure are
  1777. used by the memory management routines, the remaining bytes are available for
  1778. use by the caller (malloc, et. al., return a pointer to the first byte beyond
  1779. the memory management overhead structure).  Of course, you should never count
  1780. on any of this stuff.  I could rewrite the memory manager tomorrow and if you
  1781. use the interface which follows your code will still work properly.  If you
  1782. make assumptions about the structure of the memory management record, your code
  1783. may go up in flames on the next revision.
  1784.  
  1785.  
  1786. 6.1 MemInit
  1787.  
  1788. *          Initializes memory manager system.
  1789.  
  1790. Inputs:    DX- Number of paragraphs to reserve.
  1791.            zzzzzzseg- Segment name of last segment in your program.
  1792.            PSP- Public word variable which holds the PSP value for your
  1793.            program.
  1794.  
  1795. Outputs:   CX- Number of paragraphs actually reserved by MemInit
  1796.            Carry=0 if no error.  If carry=1, AX contains DOS error code.
  1797.  
  1798. Include:   stdlib.a
  1799.  
  1800.      This routine initializes the memory manager system.  You must call it
  1801. before using any routines which call any of the memory manager procedures
  1802. (since a good number of the stdlib routines call the memory manager, you should
  1803. get it the habit of always calling this routine.  The system will die a
  1804. horrible death if you call a memory manager routine (like malloc) without first
  1805. calling MemInit.
  1806.  
  1807.      This routine excepts you to define (and set up) two global names:
  1808. zzzzzzseg and PSP.  "zzzzzzseg" is a dummy segment which must be the name of
  1809. the very last segment defined in your program.  MemInit uses the name of this
  1810. segment to determine the address of the last byte in your program.  If you do
  1811. not declare this segment last, the memory manager will happily wipe out
  1812. anything which follows zzzzzzseg.  The "shell.asm" file provides you with a
  1813. template for your programs which properly defines this segment.
  1814.  
  1815.      PSP should be a word variable which contains the program segment prefix
  1816. value for your program.  MS-DOS passes the PSP value to your program in the DS
  1817. and ES registers.  You should save this value in the PSP variable.  Don't
  1818. forget to make PSP a public symbol in your main program's source file.  The
  1819. "shell.asm" file demonstrates how to properly set up this value.
  1820.  
  1821.      The DX register contains the number of 16-byte paragraphs you want to
  1822. reserve for the heap.  If DX contains zero, MemInit will allocate all of the
  1823. available memory to the heap.  If your program is going to allow the user to
  1824. run a copy of the command interpreter, or if your program is going to EXEC some
  1825. other program, you should not allocate all storage to the heap.  Instead, you
  1826. should reserve some memory for those programs.  By setting DX to some value
  1827. other than zero, you can tell MemInit how much memory you want to reserve for
  1828. the heap.  All left over memory will be available for other system (or program)
  1829. use.
  1830.  
  1831.      If the value is DX is larger than the amount of available RAM, MemInit
  1832. will split the available memory in half and reserve half for the heap leaving
  1833. the other half unallocated.  If you want to force this situation (to leave half
  1834. of available memory for other purposes), simply load DX with 0FFFFh before
  1835. calling MemInit.  There will never be this much memory available, so this will
  1836. force MemInit to split the available RAM between the heap and unallocated
  1837. storage.
  1838.  
  1839.      On return from MemInit, the CX register contains the number of paragraphs
  1840. actually allocated.  You can use this value to see if MemInit has actually
  1841. allocated the number of paragraphs you requested.  You can also use this value
  1842. to determine how much space is available when you elect to split the free space
  1843. between the heap and the unallocated portions.
  1844.  
  1845.      If all goes well, this routine returns the carry flag clear.  If a DOS
  1846. memory manager error occurs, this routine returns the carry flag set and the
  1847. DOS error code in the AX register.
  1848.  
  1849.      Example:
  1850.  
  1851.      ;
  1852.      ; Don't forget to set up PSP and zzzzzzseg before calling MemInit.
  1853.      ;
  1854.                      mov     dx, dx          ;Allocate all available RAM
  1855.                      MemInit
  1856.                      jc      MemoryError
  1857.      ;
  1858.      ; cx contains the number of paragraphs actually allocated.
  1859.      ;
  1860.  
  1861.  
  1862. 6.2 Malloc
  1863.  
  1864. *          Allocates storage from the heap.
  1865.  
  1866. *          Allocates blocks up to 64K long.
  1867.  
  1868. *          Very fast combination first/next fit allocation strategy
  1869.  
  1870. Inputs:    CX- Number of bytes to reserve.
  1871.  
  1872. Outputs:   CX- Number of bytes actually reserved by malloc.
  1873.            ES:DI- Pointer to first byte of memory allocated by malloc.
  1874.            Carry=0 if no error.  Carry=1 if insufficient memory
  1875.  
  1876. Include:   stdlib.a
  1877.  
  1878.      Malloc is the workhorse routine you use to allocate a block of memory.
  1879. You give it the number of bytes you need and if it finds a block large enough,
  1880. it will allocate the requested amount and return a pointer to that block.
  1881.  
  1882.      Most memory managers require a small amount of overhead for each block
  1883. they allocate.  Stdlib's (current) memory manager requires an overhead of eight
  1884. bytes.  Furthermore, the grainularity is 16 bytes.  This means that malloc
  1885. always allocates blocks of memory in paragraph multiples.  Therefore, malloc
  1886. may actually reserve more storage than you specify.  Therefore, the value
  1887. returned in CX may be somewhat greater than the requested value.  By setting
  1888. the minimum allocation size to a paragraph, I was able to reduce the overhead
  1889. and improve the speed of malloc by a considerable amount.
  1890.  
  1891.      Stdlib's memory management system does not do any garbage collection.
  1892. Doing so would place too many demands on malloc's users.  Therefore, it is
  1893. quite possible for you to fragment memory with multiple calls to malloc,
  1894. realloc, and free.  You could wind up in a situation where there is enough free
  1895. memory to satisfy your request, but there isn't a single contiguous block large
  1896. enough for the request.  Malloc treats this as an insufficient memory error and
  1897. returns with the carry flag set.
  1898.  
  1899.      If malloc cannot allocate a block of the requested size, it returns with
  1900. the carry flag set.  In this situation, the contents of ES:DI is undefined.
  1901. Attempting to dereference this pointer will produce erratic and, perhaps,
  1902. disasterous results.
  1903.  
  1904.      Example:
  1905.  
  1906.                      mov     cx, 256
  1907.                      malloc
  1908.                      jnc     GoodMalloc
  1909.                      print
  1910.                      db      "Insufficient memory to continue.",cr,lf,0
  1911.                      jmp     Quit
  1912.      GoodMalloc:     mov     es:[di], 0              ;Init string to NULL.
  1913.  
  1914.  
  1915. 6.3 Realloc
  1916.  
  1917. *          Reallocates a block of memory on the heap.
  1918.  
  1919. *          Allocates blocks up to 64K long.
  1920.  
  1921. *          Allows you to make the new block smaller or larger than the original
  1922.            block.
  1923.  
  1924. *          Automatically copies the data from the original block to the new
  1925.            block if the new block is larger than the old block.
  1926.  
  1927. Inputs:    CX- Number of bytes to reserve.
  1928.            ES:DI- Pointer to block to reallocate.
  1929.  
  1930. Outputs:   CX- Number of bytes actually reserved by realloc.
  1931.            ES:DI- Pointer to first byte of memory allocated by realloc.
  1932.            Carry=0 if no error.  Carry=1 if insufficient memory
  1933.  
  1934. Include:   stdlib.a
  1935.  
  1936.      Realloc lets you change the size of an allocated block in the heap.  It
  1937. allows you to make the block larger or smaller.  If you make the block smaller,
  1938. realloc simply frees (returns to the heap) any leftover bytes at the end of the
  1939. block.  If you make the block larger, realloc goes out and allocates a block of
  1940. the requested size, copies the bytes from the old block to the beginning of the
  1941. new block (leaving the bytes at the end of the new block uninitialized), and
  1942. then frees the old block.
  1943.  
  1944.  
  1945. 6.4 Free
  1946.  
  1947. *          Deallocates a block of memory on the heap.
  1948.  
  1949. *          Automatically coalesces all contiguous, unused, blocks on the heap.
  1950.  
  1951. *          Very fast algorithm.
  1952.  
  1953. *          Handles the situation where several active pointers may still point
  1954.            at the specified block.
  1955.  
  1956. Inputs:    ES:DI- Pointer to block to deallocate.
  1957.  
  1958. Outputs:   Carry=0 if no error.  Carry=1 if es:di doesn't point at a free
  1959.            block.
  1960.  
  1961. Include:   stdlib.a
  1962.  
  1963.      Free (possibly) deallocates storage allocated on the heap by malloc or
  1964. realloc.  Free returns this storage to the heap so other code can reuse it
  1965. later.  Note, however, that free doesn't always return storage to the heap.
  1966. The memory manager data structure keeps track of the number of pointers
  1967. currently pointing at a block on the heap (see DupPtr, below).  If you've set
  1968. up several pointers such that they point at the same block, free will not
  1969. deallocate the storage until you've freed all of the pointers which point at
  1970. that block.
  1971.  
  1972.      Free usually returns an error code (carry flag = 1) if you attempt to free
  1973. a block which is not currently allocated or if you pass it a memory address
  1974. which was not returned by malloc (or realloc).  By no means is this routine
  1975. totally robust.  If you start calling free with arbitrary pointers in es:di
  1976. (which happen to be pointing into the heap) it is possible, under certain
  1977. circumstances, to confuse free and it will attempt to free a block it really
  1978. shouldn't.  I could fix this problem by adding a lot of (slow) code to the free
  1979. routine.  However, this library is for assembly language programmers.  People
  1980. who are supposed to know what they are doing.  Therefore, I opted to sacrifice
  1981. a little safety for a lot of speed.
  1982.  
  1983.      Example:
  1984.  
  1985.                      les     di, HeapPtr
  1986.                      free
  1987.  
  1988.  
  1989. 6.5 DupPtr
  1990.  
  1991. *          Informs the memory manager that you have more than one active
  1992.            pointer pointing at a block of memory.
  1993.  
  1994. *          Prevents free from deallocating storage to a block while there are
  1995.            still some active pointers to that block.
  1996.  
  1997. Inputs:    ES:DI- Pointer to block.
  1998.  
  1999. Outputs:   Carry=0 if no error.  Carry=1 if es:di doesn't point at a free
  2000.            block.
  2001.  
  2002. Include:   stdlib.a
  2003.  
  2004.      DupPtr increments the pointer count for the block at the specified
  2005. address.  Malloc sets this counter to one.  Free decrements it by one.  If free
  2006. decrements the value and it becomes zero, free will release the storage to the
  2007. heap for other use.  By using DupPtr you can tell the memory manager that you
  2008. have several pointers pointing at the same block and that it shouldn't
  2009. deallocate the storage until you free all of those pointers.
  2010.  
  2011.      Example:
  2012.  
  2013.                      les     di, Ptr
  2014.                      DupPtr
  2015.  
  2016.  
  2017. 6.6 IsInHeap
  2018.  
  2019. *          Tells you if a pointer contains the address of a byte in the heap.
  2020.  
  2021. Inputs:    ES:DI- Pointer to block.
  2022.  
  2023. Outputs:   Carry=0 if es:di points into the heap.  Carry=1 if not.
  2024.  
  2025. Include:   stdlib.a
  2026.  
  2027.      This routine lets you know if es:di contains the address of a byte in the
  2028. heap somewhere.  It does not tell you if es:di contains a valid pointer
  2029. returned by malloc (see IsPtr, below).  For example, if es:di contains the
  2030. address of some particular element of an array (not necessarily the first
  2031. element) allocated on the heap, IsInHeap will return with the carry clear
  2032. denoting that the es:di point somewhere in the heap.  Keep in mind, that
  2033. calling this routine does not validate the pointer.  It could be pointing at a
  2034. byte which is part of the memory manager data structure rather than at actual
  2035. data (since the memory manager maintains that information within the bounds of
  2036. the heap).  This routine is mainly useful for seeing if something is allocated
  2037. on the heap as opposed to somewhere else (like your code, data, or stack
  2038. segment).
  2039.  
  2040.  
  2041. 6.7 IsPtr
  2042.  
  2043. *          Tells you if a pointer contains the address of the start of a block
  2044.            in the heap.
  2045.  
  2046. Inputs:    ES:DI- Pointer to block.
  2047.  
  2048. Outputs:   Carry=0 if es:di is a valid pointer.  Carry=1 if not.
  2049.  
  2050. Include:   stdlib.a
  2051.  
  2052.      IsPtr is much more specific than IsInHeap.  This guy returns the carry
  2053. flag clear if and only if es:di contains the address of a properly allocated
  2054. (and currently allocated) block on the heap.  This pointer must be a value
  2055. returned by malloc, realloc, or DupPtr and that block must be currently
  2056. allocated for IsPtr to return the carry flag clear.
  2057.  
  2058.  
  2059. 7 String Routines
  2060.  
  2061.      The stdlib string package supports "C" style zero-terminated strings.
  2062. Most of these routines mirror their "C" counterpart.  Of course, I've added a
  2063. few additional routines which seem useful to me.
  2064.  
  2065.  
  2066. 7.1 Strcpy, Strcpyl
  2067.  
  2068. *          Copies a zero terminated string from one buffer to another.
  2069.  
  2070. *          Does not require the use of the DS segment register.
  2071.  
  2072. Inputs:    ES:DI- Pointer to source string (Strcpy only).
  2073.            CS:RET- Pointer to source string (Strcpyl only).
  2074.            DX:SI- Pointer to destination string.
  2075.  
  2076. Outputs:   ES:DI- Points at the destination string.
  2077.  
  2078. Include:   stdlib.a
  2079.  
  2080.      Strcpy is used to copy a zero-terminated string from one location to
  2081. another.  ES:DI points at the source string, DX:SI points at the destination
  2082. address.  Strcpy copies all bytes, up to and including the zero byte, from the
  2083. source address to the destination address.  The target buffer must be large
  2084. enough to hold the string.  Strcpy performs no error checking on the size of
  2085. the destination buffer.
  2086.  
  2087.      Strcpyl copies the zero-terminated string immediately following the call
  2088. instruction to the destination address specified by DX:SI.  Again, this routine
  2089. expects you to ensure that the target buffer is large enough to hold the
  2090. result.
  2091.  
  2092.      Examples:
  2093.  
  2094.                      mov     dx, seg target
  2095.                      mov     si, offset target
  2096.                      Strcpyl
  2097.                      db      "String for Strcpyl",0
  2098.      ;
  2099.      ; Copy that string to Target2 as well, note that ES:DI already points
  2100.      ; at "Target".
  2101.      ;
  2102.                      mov     dx, seg Target2
  2103.                      mov     si, offset Target2
  2104.                      Strcpy
  2105.  
  2106.  
  2107. 7.2 StrDup, StrDupl
  2108.  
  2109. *          Duplicates a string by copying a zero-terminated string from one
  2110.            location to a newly allocated spot on the heap.
  2111.  
  2112. *          Automatically allocates sufficient storage for destination string on
  2113.            the heap.
  2114.  
  2115. *          Does not require the use of the DS segment register.
  2116.  
  2117. Inputs:    ES:DI- Pointer to source string (Strdup only).
  2118.            CS:RET- Pointer to source string (Strdupl only).
  2119.  
  2120. Outputs:   ES:DI- Points at the destination string allocated on heap.
  2121.            Carry=0 if operation successful.  Carry=0 if insufficient memory for
  2122.            new string.
  2123.  
  2124. Include:   stdlib.a
  2125.  
  2126.      Strdup and strdupl duplicate strings.  You pass them a pointer to the
  2127. string (in es:di for strdup, via the return address for strdupl) and they
  2128. allocate sufficient storage on the heap for a copy of this string.  Then these
  2129. two routines copy their source strings to the newly allocated storage and
  2130. return a pointer to the new string in ES:DI.
  2131.  
  2132.      Examples:
  2133.  
  2134.                      Strdupl
  2135.                      db      "String for Strdupl",0
  2136.                      jc      MallocError
  2137.                      mov     word ptr Dest1, di
  2138.                      mov     word ptr Dest1+2, es
  2139.      ;
  2140.      ; Create another copy of this string.  Note that es:di points at
  2141.      ; Dest1 upon entry to Strdup, but it points at the new string on
  2142.      ; exit.
  2143.      ;
  2144.                      Strdup
  2145.                      jc      MallocError
  2146.                      mov     word ptr Dest2, di
  2147.                      mov     word ptr Dest2+2, es
  2148.  
  2149.  
  2150. 7.3 Strlen
  2151.  
  2152. *          Computes the length of a zero terminated string.
  2153.  
  2154. Inputs:    ES:DI- Pointer to source string.
  2155.  
  2156. Outputs:   CX- Length of specified string.
  2157.  
  2158. Include:   stdlib.a
  2159.  
  2160.      Strlen computes the length of the string whose address appears in ES:DI.
  2161. It returns the number of characters up to, but not including, the zero
  2162. terminating byte.
  2163.  
  2164.      Example:
  2165.  
  2166.                      les     di, String
  2167.                      strlen
  2168.                      mov     sl, cx
  2169.                      printf
  2170.                      db      "Length of '%s' is %d\n",0
  2171.                      dd      String, sl
  2172.  
  2173.  
  2174. 7.4 Strcat, Strcat2, Strcatl, Strcat2l
  2175.  
  2176. *          Concatenates one string to the end of another.
  2177.  
  2178. *          Strcatl and Strcat2l allow literal string operands.
  2179.  
  2180. *          Strcat2 and Strcat2l automatically allocate storage for destination
  2181.            string.
  2182.  
  2183. Inputs:    ES:DI- Pointer to first string.
  2184.            DX:SI- Pointer to second string (Strcat & Strcat2 only).
  2185.  
  2186. Outputs:   ES:DI- Pointer to new string (Strcat2 & StrCat2l only).
  2187.            Carry=0 No error. Carry=1 Insufficient memory (Strcat2 & StrCat2l
  2188.            only).
  2189.  
  2190. Include:   stdlib.a
  2191.  
  2192.      These routines concatenate two strings together.  They differ mainly in
  2193. the location of their source and destination operands.
  2194.  
  2195.      Strcat concatenates the string pointed at by DX:SI to the end of the
  2196. string pointed at by ES:DI in memory (both strings must be zero-terminated).
  2197. The buffer pointed at by ES:DI must be large enough to hold the resulting
  2198. string.  Strcat performs no bounds checking on the data.
  2199.  
  2200.      Strcat2 works just like strcat except it does not append the second string
  2201. on to the end of the first.  Instead, Strcat2 computes the length of the two
  2202. strings and attempts to allocate this much storage on the heap.  If it is
  2203. unsuccessful, Strcat2 returns with the carry flag set.  If it successfully
  2204. allocates this storage on the heap, it copies the string pointed at by es:di to
  2205. the heap and then concatenates the string dx:si points at to the end of this
  2206. string on the heap and returns with the carry flag clear and es:di pointing at
  2207. the new string on the heap.
  2208.  
  2209.      Strcatl and Strcat2l work just like Strcat and Strcat2 except you supply
  2210. the second string as a literal constant immediately after the call rather than
  2211. pointing dx:si at it.
  2212.  
  2213.      Examples:
  2214.  
  2215.                      les     di, String1
  2216.                      mov     dx, seg String2
  2217.                      lea     si, String2
  2218.                      Strcat                  ;String1 <- String1 + String2
  2219.      ;
  2220.                      les     di, String1
  2221.                      Strcatl
  2222.                      db      "Appended String",0
  2223.      ;
  2224.                      les     di, String1
  2225.                      mov     dx, seg String2
  2226.                      lea     si, String2
  2227.                      Strcat2                 ;NewString<-String1+String2
  2228.                      puts
  2229.                      free
  2230.      ;
  2231.                      les     di, String1
  2232.                      Strcat2l
  2233.                      db      "Appended String",0
  2234.                      puts
  2235.                      free
  2236.  
  2237.  
  2238. 7.5 Strchr
  2239.  
  2240. *          Searches for a single character inside a string.
  2241.  
  2242. Inputs:    ES:DI- Pointer to string.
  2243.            AL- Character to search for.
  2244.  
  2245. Outputs:   CX- Position (starting at zero) where Strchr found the character.
  2246.            Carry=0 if Strchr found the character.
  2247.            Carry=1 if the character wasn't present in the string.
  2248.  
  2249. Include:   stdlib.a
  2250.  
  2251.      Strchr locates the first occurrence of a character within a string.  It
  2252. searches through the zero-terminated string pointed at by es:di for the
  2253. character passed in AL.  If it locates the character, it returns the position
  2254. of that character in the CX register.  The first character in the string
  2255. corresponds to location zero.  If the character is not in the string, Strchr
  2256. returns the carry flag set.  CX's value is undefined in that case.  If Strchr
  2257. locates the character in the string, it returns with the carry flag clear.
  2258.  
  2259.      Example:
  2260.  
  2261.                      les     di, String
  2262.                      mov     al, Char2Find
  2263.                      strchr
  2264.                      jc      NotPresent
  2265.                      mov     CharPosn, cx
  2266.  
  2267.  
  2268. 7.6 Strstr, Strstrl
  2269.  
  2270. *          Searches for a substring inside another string.
  2271.  
  2272. Inputs:    ES:DI- Pointer to string.
  2273.            DX:SI- Pointer to substring (strstr).
  2274.            CS:RET- Pointer to substring (strstrl).
  2275.  
  2276. Outputs:   CX- Position (starting at zero) where Strstr/Strstrl found the
  2277.            character.
  2278.            Carry=0 if Strstr/Strstrl found the character.
  2279.            Carry=1 if the character wasn't present in the string.
  2280.  
  2281. Include:   stdlib.a
  2282.  
  2283.      Strstr searches for the position of a substring within another string.
  2284. ES:DI points at the string to search through, DX:SI points at the substring.
  2285. Strstr returns the index into ES:DI's string where DX:SI's string is found.  If
  2286. the string is found, Strstr returns with the carry flag clear and CX contains
  2287. the (zero-based) index into the string.  If Strstr cannot locate the substring
  2288. within the string ES:DI points at, it returns the carry flag set.
  2289.  
  2290.      Strstrl works just like Strstr except it expects the substring to search
  2291. for immediately after the call instruction (rather than passing this address in
  2292. DX:SI).
  2293.  
  2294.      Examples:
  2295.  
  2296.                      les     di, MainString
  2297.                      lea     si, Substring
  2298.                      mov     dx, seg Substring
  2299.                      strstr
  2300.                      jc      NoMatch
  2301.                      mov     i, cx
  2302.                      printf
  2303.                      db      "Found the substring '%s' at location %i\n",0
  2304.                      dd      Substring, i
  2305.                      jmp     Done
  2306.      ;
  2307.      NoMatch:        print
  2308.                      db      "Could not find the substring.",cr,lf,0
  2309.      Done:           les     di, MainString
  2310.                      strstrl
  2311.                      db      "test",0
  2312.                      jc      NoMatch2
  2313.                      print   "Found 'test' in the string",cr,lf,0
  2314.                      jmp     Done2
  2315.      ;
  2316.      NoMatch2:       print
  2317.                      db      "Did not find 'test' in the string",cr,lf,0
  2318.      Done2:
  2319.  
  2320.  
  2321. 7.7 Strcmp, Strcmpl
  2322.  
  2323. *          Compares two strings.
  2324.  
  2325. *          Reflects comparison in 8086 condition code flags.
  2326.  
  2327. Inputs:    ES:DI- Pointer to first string.
  2328.            DX:SI- Pointer to second string (strcmp).
  2329.            CS:RET- Pointer to substring (strcmpl).
  2330.  
  2331. Outputs:   CX- Position (starting at zero) where the two strings differ.
  2332.            Flags- hold the result of the comparison (should use unsigned
  2333.            branches).
  2334.  
  2335. Include:   stdlib.a
  2336.  
  2337.      Strcmp and strcmpl compare two strings.  Strcmp compares the string which
  2338. es:di points at to the string which dx:si points at.  Strcmpl compares the
  2339. string which es:di points at to the string immediately following the call
  2340. instruction in the code stream.  Strcmp(l) reflects the status of this
  2341. comparison in the flags register.  Immediately upon return from strcmp(l) you
  2342. can use the unsigned jump instructions to test the comparison between the two
  2343. strings.  Also (upon return), the CX register contains the index into the
  2344. strings where they are different (if the two strings are equal, Strcmp(l)
  2345. returns with CX containing the offset of the zero byte in the two strings.
  2346.  
  2347.      Examples:
  2348.  
  2349.                      les     di, String1
  2350.                      mov     dx, seg String2
  2351.                      lea     si, String2
  2352.                      strcmp
  2353.                      jae     s1GEs2
  2354.                      mov     i, cx
  2355.                      printf
  2356.                      db      "String1 is less than String2 and they "
  2357.                      db      "differ at position %i\n",0
  2358.                      dd      i
  2359.      ;
  2360.                      les     di, String3
  2361.                      strcmpl
  2362.                      db      "Hello",0
  2363.                      jbe     S3BEHello
  2364.      ;
  2365.  
  2366. 7.8 Stricmp, Stricmpl
  2367.  
  2368. *          Compares two strings ignoring differences in alphabetic case.
  2369.  
  2370. *          Reflects comparison in 8086 condition code flags.
  2371.  
  2372. Inputs:    ES:DI- Pointer to first string.
  2373.            DX:SI- Pointer to second string (stricmp).
  2374.            CS:RET- Pointer to substring (stricmpl).
  2375.  
  2376. Outputs:   CX- Position (starting at zero) where the two strings differ.
  2377.            Flags- hold the result of the comparison (should use unsigned
  2378.            branches).
  2379.  
  2380. Include:   stdlib.a
  2381.  
  2382.      Stricmp and Stricmpl work just like Strcmp and Strcmpl except that these
  2383. two routines are case insenstive.  Strcmp and Strcmpl treat "GETS" and "gets"
  2384. as different strings.  Stricmp and Stricmpl treat these two strings as equal.
  2385.  
  2386.  
  2387. 7.9 Strupr, Strupr2
  2388.  
  2389. *          Converts all of the lower case characters in a string to upper case.
  2390.  
  2391. *          Converts the characters in place (Strupr) or creates a new string on
  2392.            the heap for the converted string (Strupr2).
  2393.  
  2394. Inputs:    ES:DI- Pointer to string.
  2395.  
  2396. Outputs:   ES:DI- Pointer to new string on heap (Strupr2 only).
  2397.            Carry=1 if memory allocation error (Strupr2 only).
  2398.  
  2399. Include:   stdlib.a
  2400.  
  2401.      Strupr and Strupr2 convert the alphabetic characters in a string to upper
  2402. case.  You pass the address of the string containing the characters you want to
  2403. convert in ES:DI.  Strupr converts the characters in place.  That is, it will
  2404. actually modify the string you pass to it.  Strupr2 first calls strdup to
  2405. duplicate the string (on the heap) and then it converts the characters in this
  2406. duplicate string to upper case, returning the pointer to the new string is
  2407. ES:DI.
  2408.  
  2409.      Examples:
  2410.  
  2411.                      les     di, Str2Cnvrt
  2412.                      strupr
  2413.                      les     di, Str2Cnvrt
  2414.                      puts
  2415.                      les     di, Str2Cnvrt2
  2416.                      strupr2
  2417.                      puts
  2418.                      free
  2419.  
  2420.  
  2421. 7.10 Strlwr, Strlwr2
  2422.  
  2423. *          Converts all of the upper case characters in a string to lower case.
  2424.  
  2425. *          Converts the characters in place (Strlwr) or creates a new string on
  2426.            the heap for the converted string (Strlwr2).
  2427.  
  2428. Inputs:    ES:DI- Pointer to string.
  2429.  
  2430. Outputs:   ES:DI- Pointer to new string on heap (Strlwr2 only).
  2431.            Carry=1 if memory allocation error (Strlwr2 only).
  2432.  
  2433. Include:   stdlib.a
  2434.  
  2435.      Strlwr and Strlwr2 convert the alphabetic characters in a string to lower
  2436. case.  You pass the address of the string containing the characters you want to
  2437. convert in ES:DI.  Strlwr converts the characters in place.  That is, it will
  2438. actually modify the string you pass to it.  Strlwr2 first calls strdup to
  2439. duplicate the string (on the heap) and then it converts the characters in this
  2440. duplicate string to lower case, returning the pointer to the new string is
  2441. ES:DI.
  2442.  
  2443.      Examples:
  2444.  
  2445.                      les     di, Str2Cnvrt
  2446.                      strlwr
  2447.                      les     di, Str2Cnvrt
  2448.                      puts
  2449.                      les     di, Str2Cnvrt2
  2450.                      strlwr2
  2451.                      puts
  2452.                      free
  2453.  
  2454.  
  2455. 7.11 Strset, Strset2
  2456.  
  2457. *          Initializes all the characters in a string to a single value.
  2458.  
  2459. *          Automatically allocates storage on the heap for the string (Strset2
  2460.            only).
  2461.  
  2462. Inputs:    ES:DI- Pointer to string (Strset only)
  2463.            AL- Character to initialize the string with.
  2464.            CX- Length of string (Strset2 only).
  2465.  
  2466. Outputs:   ES:DI- Pointer to new string on heap (Strset2 only).
  2467.            Carry=1 if memory allocation error (Strset2 only).
  2468.  
  2469. Include:   stdlib.a
  2470.  
  2471.      Strset and Strset2 initialize strings such that each element of the string
  2472. contains the same value (passed in AL).  Strset overwrites the data in an
  2473. existing string, replacing the characters previously in the string.  To use
  2474. Strset, simply load ES:DI with the address of a string, load AL with the
  2475. character you want to overwrite the string with, and then call Strset.  Strset
  2476. will replace each existing character (up to the zero terminating byte) of the
  2477. string with the character in AL.
  2478.  
  2479.      Strset2 lets you create a brand-new string.  You pass the initialization
  2480. character in AL and the length of the string in CX.  Strset2 allocates CX+1
  2481. bytes on the heap and initializes the first CX bytes to the value in AL.  It
  2482. stores a zero in the last memory location.
  2483.  
  2484.      Examples:
  2485.  
  2486.                      lesi    di, Str2Cnvrt
  2487.                      mov     al, '*'
  2488.                      Strset
  2489.      ;
  2490.                      mov     al, '#'
  2491.                      mov     cx, 32
  2492.                      Strset2
  2493.                      puts
  2494.                      free
  2495.      ;
  2496.  
  2497. 7.12 Strspan, Strspanl
  2498.  
  2499. *          Allows you to skip over successive characters in a string.
  2500.  
  2501. *          Very compact implementation.
  2502.  
  2503. Inputs:    ES:DI- Pointer to string to scan.
  2504.            DX:SI- Pointer to character set (Strspan only).
  2505.            CS:RET- Pointer to character set (Strspanl only).
  2506.  
  2507. Outputs:   First position where Strspan(l) could not find a character in the
  2508.            attendant character set.  Points at the zero terminating byte of the
  2509.            string if all of the characters in the string were present in the
  2510.            set.
  2511.  
  2512. Include:   stdlib.a
  2513.  
  2514.      Strspan(l) scans a string counting the number of characters which are
  2515. present in a second string (which represents a character set).  While each
  2516. successive character in the source string is present in the character set,
  2517. Strspan(l) advances past it.  ES:DI points at a zero-terminated string of
  2518. characters to check.  DX:SI (strspan) or CS:RET (strspanl) points at another
  2519. zero-terminated string containing the set of characters to compare against.
  2520. While the character that ES:DI points at is present (anywhere) in the character
  2521. set string, the routine advances to the next character and bumps a counter by
  2522. one.  Upon encountering a character which is not in the character set string,
  2523. the routine terminates and returns the number of characters (i.e., an index
  2524. into the string) where the mismatch occurred.
  2525.  
  2526.      Although strspan (and, especially, strspanl) is very compact and
  2527. convenient to use, it is not particularly efficient.  The character set
  2528. routines described in the next section provide a much faster alternative at the
  2529. expense of a little more space.
  2530.  
  2531.      Examples:
  2532.  
  2533.                      les     di, String
  2534.                      mov     dx, seg CharSet
  2535.                      lea     si, CharSet
  2536.                      strspan
  2537.                      mov     i, cx
  2538.                      printf
  2539.                      db      "The first char which is not in CharSet "
  2540.                      db      "occurs at position %d in String.\n",0
  2541.                      dd      i
  2542.      ;
  2543.                      les     di, String
  2544.                      db      "aeiou",0
  2545.                      mov     j, cx
  2546.                      printf
  2547.                      db      "The first char which is not a vowel "
  2548.                      db      "occurs at position %d in String.\n",0
  2549.                      dd      j
  2550.  
  2551.  
  2552. 7.13 Strcspan, Strcspanl
  2553.  
  2554. *          Allows you to skip past characters in a string which are not members
  2555.            of a particular character set.
  2556.  
  2557. Inputs:    ES:DI- Pointer to string to scan.
  2558.            DX:SI- Pointer to character set (Strcspan only).
  2559.            CS:RET- Pointer to character set (Strcspanl only).
  2560.  
  2561. Outputs:   First position where Strcspan(l) found a character in the attendant
  2562.            character set.  Points at the zero terminating byte of the string if
  2563.            none of the characters in the string were in the set.
  2564.  
  2565. Include:   stdlib.a
  2566.  
  2567.      These two routines work just like strspan and strspanl except they skip
  2568. over characters which are not in the set rather than skipping over characters
  2569. that are in the associated character set.
  2570.  
  2571.  
  2572. 8 Character Set Routines
  2573.  
  2574.      The character set routines let you deal with groups of characters as a set
  2575. rather than a string.  A set is an unordered collection of objects where
  2576. membership (presence or absence) is the only important quality.  I designed the
  2577. stdlib set routines to let you quickly check to see if an ASCII character is in
  2578. a set, to quickly add characters to a set or remove characters from a set.
  2579. These operations are the ones most commonly used on character sets.  The other
  2580. operations (like union, intersection, difference, etc.) are useful, but don't
  2581. enjoy the popularity of use as the former routines.   Therefore, I've optimized
  2582. the data structure for sets to handle the membership and add/delete operations
  2583. at the slight expense of the others.
  2584.  
  2585.      Character sets are implemented via bit vectors.  A "1" bit means that an
  2586. item is present in the set and a "0" bit means that the item is absent from the
  2587. set.  The most common implementation of a character set is to use 32
  2588. consecutive bytes, eight bits per, giving 256 bits (one bit for each character
  2589. in the character set).  While this makes certain operations (like assignment,
  2590. union, intersection, etc.) fast and convenient.  Other operations (membership,
  2591. add/remove items), however, run much slower.  Since these are the more
  2592. important operations, I've chosen a different data structure to represent
  2593. sets.  A faster approach is to simply use a byte value for each item in the
  2594. set.  This offers a major advantage over the 32-bit scheme: for operations like
  2595. membership it's very fast (since all you've got to do is index into an array
  2596. and test the resulting value).  It has two drawbacks: first, operations like
  2597. set assignment, union, difference, etc., require 256 operations rather than
  2598. 32.  Second, it takes eight times as much memory.
  2599.  
  2600.      The first drawback, speed, is of little consequence.  You'll rarely use
  2601. the operations so affected, so the fact that they run a little slower will be
  2602. of little consequence.  Wasting 224 bytes is a problem however.  Especially if
  2603. you have a lot of character sets.
  2604.  
  2605.      The approach I've used is to allocate 272 bytes.  The first eight bytes
  2606. contain bit masks, 1, 2, 4, 8, 16, 32, 64, and 128.  These masks tell you which
  2607. bit in the following 264 bytes is associated with the set.  This lets me pack
  2608. eight sets into 272 bytes (34 bytes per character set).   This provides almost
  2609. the speed of the 256-byte set with only a two byte overhead.
  2610.  
  2611.      In the stdlib.a file there is a macro that lets you defined a group of
  2612. character sets:  set.  You use the macro as follows:
  2613.  
  2614.                      set     set1, set2, set3, ..., set8
  2615.  
  2616.      You must supply between one and eight labels in the operand field.  These
  2617. are the names of the sets you want to create.  The set macro automatically
  2618. attaches these labels to the appropriate mask bytes in the set.  The actual bit
  2619. patterns for the set begin eight bytes later (from each label).  Therefore, the
  2620. byte corresponding to chr(0) is staggered by one byte for each set (which
  2621. explains the other eight bytes needed above and beyond the 256 required for the
  2622. set).
  2623.  
  2624.      When using the set manipulation routines, you should always pass the
  2625. address of the mask byte (i.e., the seg/offset of one of the labels above) to
  2626. the particular set manipulation routine you're using.  Passing the address of
  2627. the structure created with the macro above will reference only the first set in
  2628. the group.
  2629.  
  2630.      Note that you can use the set operations for fast pattern matching
  2631. applications.  The set membership operation, for example, is much faster than
  2632. the strspan routine found in the string package.  Proper use of character sets
  2633. can produce a program which runs much faster than some of the equivalent string
  2634. operations.
  2635.  
  2636.  
  2637. 8.1 Createsets
  2638.  
  2639. *          Allocates storage for eight character sets on the stack.
  2640.  
  2641. Inputs:    None.
  2642.  
  2643. Outputs:   ES:DI- Pointer to eight sets.
  2644.            Carry=0 if no error.
  2645.            Carry=1 if insufficient memory to allocate storage for sets.
  2646.  
  2647. Include:   stdlib.a
  2648.  
  2649.      Createsets allocates 272 bytes on the heap.  This is sufficient room for
  2650. eight character sets.  It then initializes the first eight bytes of this
  2651. storage with the proper mask values for each set.  Location es:0[di] gets set
  2652. to 1, location es:1[di] gets 2, location es:2[di] gets 4, etc.  The createsets
  2653. routine also initializes all of the sets to the empty set by clearing all the
  2654. bits to zero.
  2655.  
  2656.      Example:
  2657.  
  2658.                      createsets
  2659.                      jc      NoMemory
  2660.                      mov     word ptr SetPtr, di
  2661.                      mov     word ptr SetPtr+2, es
  2662.      ;
  2663.  
  2664.  
  2665. 8.2 EmptySet
  2666.  
  2667. *          Clears all of the bits for a particular set to zero.
  2668.  
  2669. Inputs:    ES:DI- pointer to first byte of desired set.
  2670.  
  2671. Outputs:   None.
  2672.  
  2673. Include:   stdlib.a
  2674.  
  2675.      Emptyset clears out the bits in a character set to zero (thereby setting
  2676. it to the empty set).  Upon entry, es:di must point at the first byte of the
  2677. character set you want to clear.  Note that this is not the address returned by
  2678. createsets.  The first eight bytes of a character set structure are the
  2679. addresses of eight different sets.  ES:DI must point at one of these bytes upon
  2680. entry into emptyset.
  2681.  
  2682.      Example:
  2683.  
  2684.                      les     di, SetPtr
  2685.                      add     di, 3           ;Point at 4th set in group.
  2686.                      emptyset
  2687.      ;
  2688.  
  2689.  
  2690. 8.3 RangeSet
  2691.  
  2692. *          Adds all of the elements between two values to a set.
  2693.  
  2694. Inputs:    ES:DI- pointer to first byte of desired set.
  2695.            AL- Lower bounds for range of items.
  2696.            AH- Upper bound for range (must be greater than AL).
  2697.  
  2698. Outputs:   None.
  2699.  
  2700. Include:   stdlib.a
  2701.  
  2702.      Rangeset adds in (via a UNION operation) to a set a range of values.
  2703.  
  2704.      Example:
  2705.  
  2706.                      les     di, SetPtr
  2707.                      add     di, 4           ;Point at 5th set in group.
  2708.                      mov     al, 'A'         ;Add in the alphabetic chars
  2709.                      mov     ah, 'Z'
  2710.                      rangeset
  2711.      ;
  2712.  
  2713.  
  2714. 8.4 Addstr, Addstrl
  2715.  
  2716. *          Adds all of the characters from a string to a set.
  2717.  
  2718. Inputs:    ES:DI- pointer to first byte of desired set.
  2719.            DX:SI- pointer to string to add to set (Addstr only).
  2720.            CS:RET-pointer to string to add to set (Addstrl only).
  2721.  
  2722. Outputs:   None.
  2723.  
  2724. Include:   stdlib.a
  2725.  
  2726.      Addstr lets you add a group of characters to a set by specifying a string
  2727. containing the characters you want in the set.  To Addstr you pass a pointer to
  2728. a zero-terminated string in dx:si.  Addstr will add (union) each character from
  2729. this string into the set.  Addstrl lets you specify the string as a literal
  2730. constant immediately after the call to addstrl.
  2731.  
  2732.      Example:
  2733.  
  2734.                      les     di, SetPtr
  2735.                      add     di, 1           ;Point at 2nd set in group.
  2736.                      mov     dx, seg CharStr ;Pointer to string containing
  2737.                      lea     si, CharStr     ; chars to add to set.
  2738.                      addstr                  ;Union in these characters.
  2739.      ;
  2740.                      les     di, SetPtr      ;Point at first set in group.
  2741.                      addstrl
  2742.                      db      "AaBbCcDdEeFf0123456789",0
  2743.      ;
  2744.  
  2745.  
  2746. 8.5 Rmvstr
  2747.  
  2748. *          Removes all of the characters in a string from a set.
  2749.  
  2750. Inputs:    ES:DI- pointer to first byte of desired set.
  2751.            DX:SI- pointer to string to remove from set (Rmvstr only).
  2752.            CS:RET-pointer to string to remove from set (Rmvstrl only).
  2753.  
  2754. Outputs:   None.
  2755.  
  2756. Include:   stdlib.a
  2757.  
  2758.      Rmvstr is the converse operation to Addstr.  It removes from a set the
  2759. characters appearing in the associated character string.  Rmvstrl works the
  2760. same way except you pass the string of characters immediately after the call
  2761. rather than via a pointer in DX:SI.
  2762.  
  2763.      Example:
  2764.  
  2765.                      les     di, SetPtr
  2766.                      add     di, 1           ;Point at 2nd set in group.
  2767.                      mov     dx, seg CharStr ;Pointer to string containing
  2768.                      lea     si, CharStr     ; chars to add to set.
  2769.                      rmvstr                  ;Remove these characters.
  2770.      ;
  2771.                      les     di, SetPtr      ;Point at first set in group.
  2772.                      rmvstrl
  2773.                      db      "AaBbCcDdEeFf0123456789",0
  2774.      ;
  2775.  
  2776.  
  2777. 8.6 AddChar
  2778.  
  2779. *          Adds a single character to a set.
  2780.  
  2781. Inputs:    ES:DI- pointer to first byte of desired set.
  2782.            AL-    character to add to the set.
  2783.  
  2784. Outputs:   None.
  2785.  
  2786. Include:   stdlib.a
  2787.  
  2788.      AddChar lets you add a single character (passed in AL) to a set.
  2789.  
  2790.      Example:
  2791.  
  2792.                      les     di, SetPtr
  2793.                      add     di, 1           ;Point at 2nd set in group.
  2794.                      mov     al, Ch2Add      ;Character to add to set.
  2795.                      addchar
  2796.  
  2797.  
  2798. 8.7 RmvChar
  2799.  
  2800. *          Removes a single character from a set.
  2801.  
  2802. Inputs:    ES:DI- pointer to first byte of desired set.
  2803.            AL-    character to remove from the set.
  2804.  
  2805. Outputs:   None.
  2806.  
  2807. Include:   stdlib.a
  2808.  
  2809.      RmvChar lets you remove a single character (passed in AL) from a set.
  2810.  
  2811.      Example:
  2812.  
  2813.                      les     di, SetPtr
  2814.                      add     di, 1           ;Point at 2nd set in group.
  2815.                      mov     al, Ch2Rmv      ;Character to add to set.
  2816.                      rmvchar
  2817.  
  2818.  
  2819. 8.8 Member
  2820.  
  2821. *          Checks a character value to see if it is in the set..
  2822.  
  2823. Inputs:    ES:DI- pointer to first byte of desired set.
  2824.            AL-    character to check.
  2825.  
  2826. Outputs:   Zero flag=1 if character is in the set.
  2827.            Zero flag=0 if character is not in the set.
  2828.  
  2829. Include:   stdlib.a
  2830.  
  2831.      Member lets you check for set membership, that is, it lets you see if a
  2832. character value is present in some set.  This routine is probably the
  2833. most-often called routine in the collection of set routines.
  2834.  
  2835.      Example:
  2836.  
  2837.                      les     di, SetPtr
  2838.                      add     di, 7           ;Point at 8th set in group.
  2839.                      mov     al, Ch2Chk      ;Character to check.
  2840.                      member
  2841.                      je      IsInSet
  2842.      ;
  2843.  
  2844. 8.9 CopySet
  2845.  
  2846. *          Copies one set to another.
  2847.  
  2848. Inputs:    ES:DI- pointer to first byte of destination set.
  2849.            DX:SI- pointer to first byte of source set.
  2850.  
  2851. Outputs:   None.
  2852.  
  2853. Include:   stdlib.a
  2854.  
  2855.      CopySet copies the items from one set to another.  This is a straight
  2856. assignment not a union operation.  After the operation the destination set is
  2857. identical to the source set, both in terms of the element present in the set
  2858. and absent from the set.
  2859.  
  2860.      Example:
  2861.  
  2862.                      les     di, SetPtr
  2863.                      add     di, 7           ;Point at 8th set in group.
  2864.                      mov     dx, seg SetPtr2 ;Point at first set in group.
  2865.                      lea     si, SetPtr2
  2866.                      copyset
  2867.      ;
  2868.  
  2869. 8.10 SetUnion
  2870.  
  2871. *          Unions (adds) the members of one set into another.
  2872.  
  2873. Inputs:    ES:DI- pointer to first byte of destination set.
  2874.            DX:SI- pointer to first byte of source set.
  2875.  
  2876. Outputs:   None.
  2877.  
  2878. Include:   stdlib.a
  2879.  
  2880.      The SetUnion routine computes the union of two sets.  That is, it adds all
  2881. of the items present in a source set to a destination set.  This operation
  2882. preserves items present in the destination set before the SetUnion operation.
  2883.  
  2884.      Example:
  2885.  
  2886.                      les     di, SetPtr
  2887.                      add     di, 7           ;Point at 8th set in group.
  2888.                      mov     dx, seg SetPtr2 ;Point at first set in group.
  2889.                      lea     si, SetPtr2
  2890.                      unionset
  2891.      ;
  2892.  
  2893. 8.11 SetIntersect
  2894.  
  2895. *          Computes the intersection of two sets.
  2896.  
  2897. Inputs:    ES:DI- pointer to first byte of destination set.
  2898.            DX:SI- pointer to first byte of source set.
  2899.  
  2900. Outputs:   None.
  2901.  
  2902. Include:   stdlib.a
  2903.  
  2904.      Setintersect computes the intersection of two sets, leaving the result in
  2905. the destination set.  The new set consists only of those items which previously
  2906. appeared in both the source and destination sets.
  2907.  
  2908.      Example:
  2909.  
  2910.                      les     di, SetPtr
  2911.                      add     di, 7           ;Point at 8th set in group.
  2912.                      mov     dx, seg SetPtr2 ;Point at first set in group.
  2913.                      lea     si, SetPtr2
  2914.                      setintersect
  2915.      ;
  2916.  
  2917. 8.12 SetDifference
  2918.  
  2919. *          Computes the difference of two sets.
  2920.  
  2921. Inputs:    ES:DI- pointer to first byte of destination set.
  2922.            DX:SI- pointer to first byte of source set.
  2923.  
  2924. Outputs:   None.
  2925.  
  2926. Include:   stdlib.a
  2927.  
  2928.      SetDifference computes the result of (ES:DI) := (ES:DI) - (DX:SI).  The
  2929. destination set is left with its original items minus those items which are
  2930. also in the source set.
  2931.  
  2932.      Example:
  2933.  
  2934.                      les     di, SetPtr
  2935.                      add     di, 7           ;Point at 8th set in group.
  2936.                      mov     dx, seg SetPtr2 ;Point at first set in group.
  2937.                      lea     si, SetPtr2
  2938.                      setdifference
  2939.      ;
  2940.  
  2941. 8.13 NextItem
  2942.  
  2943. *          Locates the next (first) available item in a set.
  2944.  
  2945. *          Searches for items in ascending order using the ASCII collating
  2946.            sequence.
  2947.  
  2948. Inputs:    ES:DI- pointer to first byte of set.
  2949.  
  2950. Outputs:   AL- Contains first item found in set (zero if the set is empty).
  2951.  
  2952. Include:   stdlib.a
  2953.  
  2954.      NextItem searches for the next available item in a set.  It returns the
  2955. ASCII code of the character it finds in the AL register.  If the set is empty,
  2956. NextItem returns zero (since chr(0) is illegal).  This call does not affect the
  2957. set in any way.  In particular, after the call the character located will still
  2958. be present in the set.
  2959.  
  2960.      Example:
  2961.  
  2962.                      les     di, SetPtr
  2963.                      add     di, 7           ;Point at 8th set in group.
  2964.                      nextitem
  2965.                      mov     ch2, al
  2966.      ;
  2967.  
  2968. 8.14 RmvItem
  2969.  
  2970. *          Locates the next (first) available item in a set and then removes
  2971.            that item from the set.
  2972.  
  2973. *          Searches for items in ascending order using the ASCII collating
  2974.            sequence.
  2975.  
  2976. Inputs:    ES:DI- pointer to first byte of set.
  2977.  
  2978. Outputs:   AL- Contains first item found in set (zero if the set is empty).
  2979.  
  2980. Include:   stdlib.a
  2981.  
  2982.      RmvItem searches for the next available item in a set.  It returns the
  2983. ASCII code of the character it finds in the AL register and removes that item
  2984. from the set.  If the set is empty, NextItem returns zero (since chr(0) is
  2985. illegal).
  2986.  
  2987.      Example:
  2988.  
  2989.                      les     di, SetPtr
  2990.                      add     di, 7           ;Point at 8th set in group.
  2991.                      rmvitem
  2992.                      mov     ch3, al
  2993.      ;
  2994.